nanoc 4.4.3 → 4.4.4
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/Gemfile.lock +3 -3
- data/NEWS.md +6 -0
- data/lib/nanoc.rb +1 -0
- data/lib/nanoc/base/compilation/outdatedness_checker.rb +82 -137
- data/lib/nanoc/base/compilation/outdatedness_reasons.rb +16 -5
- data/lib/nanoc/base/entities.rb +4 -0
- data/lib/nanoc/base/entities/dependency.rb +28 -0
- data/lib/nanoc/base/entities/document.rb +1 -1
- data/lib/nanoc/base/entities/outdatedness_status.rb +23 -0
- data/lib/nanoc/base/entities/props.rb +76 -0
- data/lib/nanoc/base/entities/rule_memory.rb +7 -0
- data/lib/nanoc/base/plugin_registry.rb +1 -1
- data/lib/nanoc/base/repos/dependency_store.rb +22 -58
- data/lib/nanoc/base/services.rb +2 -0
- data/lib/nanoc/base/services/action_provider.rb +2 -2
- data/lib/nanoc/base/services/filter.rb +1 -1
- data/lib/nanoc/base/services/outdatedness_rule.rb +21 -0
- data/lib/nanoc/base/services/outdatedness_rules.rb +121 -0
- data/lib/nanoc/cli/commands/show-data.rb +4 -4
- data/lib/nanoc/rule_dsl/action_provider.rb +0 -4
- data/lib/nanoc/rule_dsl/rule_memory_calculator.rb +0 -12
- data/lib/nanoc/version.rb +1 -1
- data/test/base/test_outdatedness_checker.rb +1 -1
- data/test/checking/checks/test_html.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8f94a3171ddf9ebc26963938e4399d7075b1e5a
|
4
|
+
data.tar.gz: 81f10a1af119995497a8a11ff564ecc0408c3703
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78b10318c7b1160ce58257201d03f82295db7cd027bf6cb1e5265c0bbcde0cacbf9907ee140166c51d572c1b8ca1a4c53ed93af8dfafdba3ff37f322b4110cf2
|
7
|
+
data.tar.gz: 67260b141c829d973f341bf469a0fae490232d628265a9e55bc6e89a73a672b8811505702b8c0327694ea6e098db5b8d16462580b920e319ddea141510df3521
|
data/Gemfile.lock
CHANGED
@@ -9,7 +9,7 @@ GIT
|
|
9
9
|
PATH
|
10
10
|
remote: .
|
11
11
|
specs:
|
12
|
-
nanoc (4.4.
|
12
|
+
nanoc (4.4.4)
|
13
13
|
cri (~> 2.3)
|
14
14
|
hamster (~> 3.0)
|
15
15
|
parallel (~> 1.9)
|
@@ -51,7 +51,7 @@ GEM
|
|
51
51
|
sass (>= 3.3.0, < 3.5)
|
52
52
|
compass-import-once (1.0.5)
|
53
53
|
sass (>= 3.2, < 3.5)
|
54
|
-
concurrent-ruby (1.0.
|
54
|
+
concurrent-ruby (1.0.3)
|
55
55
|
contracts (0.14.0)
|
56
56
|
coveralls (0.8.17)
|
57
57
|
json (>= 1.8, < 3)
|
@@ -332,7 +332,7 @@ GEM
|
|
332
332
|
execjs (>= 0.3.0, < 3)
|
333
333
|
unicode-display_width (1.1.2)
|
334
334
|
vcr (3.0.3)
|
335
|
-
w3c_validators (1.3)
|
335
|
+
w3c_validators (1.3.1)
|
336
336
|
json (~> 2.0)
|
337
337
|
nokogiri (~> 1.6)
|
338
338
|
webmock (2.3.1)
|
data/NEWS.md
CHANGED
data/lib/nanoc.rb
CHANGED
@@ -3,6 +3,73 @@ module Nanoc::Int
|
|
3
3
|
#
|
4
4
|
# @api private
|
5
5
|
class OutdatednessChecker
|
6
|
+
class Basic
|
7
|
+
extend Nanoc::Int::Memoization
|
8
|
+
|
9
|
+
include Nanoc::Int::ContractsSupport
|
10
|
+
|
11
|
+
Rules = Nanoc::Int::OutdatednessRules
|
12
|
+
|
13
|
+
RULES_FOR_ITEM_REP =
|
14
|
+
[
|
15
|
+
Rules::RulesModified,
|
16
|
+
Rules::PathsModified,
|
17
|
+
Rules::ContentModified,
|
18
|
+
Rules::AttributesModified,
|
19
|
+
Rules::NotWritten,
|
20
|
+
Rules::CodeSnippetsModified,
|
21
|
+
Rules::ConfigurationModified,
|
22
|
+
].freeze
|
23
|
+
|
24
|
+
RULES_FOR_LAYOUT =
|
25
|
+
[
|
26
|
+
Rules::RulesModified,
|
27
|
+
Rules::ContentModified,
|
28
|
+
Rules::AttributesModified,
|
29
|
+
].freeze
|
30
|
+
|
31
|
+
contract C::KeywordArgs[outdatedness_checker: OutdatednessChecker, reps: Nanoc::Int::ItemRepRepo] => C::Any
|
32
|
+
def initialize(outdatedness_checker:, reps:)
|
33
|
+
@outdatedness_checker = outdatedness_checker
|
34
|
+
@reps = reps
|
35
|
+
end
|
36
|
+
|
37
|
+
contract C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] => C::Maybe[OutdatednessStatus]
|
38
|
+
def outdatedness_status_for(obj)
|
39
|
+
case obj
|
40
|
+
when Nanoc::Int::ItemRep
|
41
|
+
apply_rules(RULES_FOR_ITEM_REP, obj)
|
42
|
+
when Nanoc::Int::Item
|
43
|
+
apply_rules_multi(RULES_FOR_ITEM_REP, @reps[obj])
|
44
|
+
when Nanoc::Int::Layout
|
45
|
+
apply_rules(RULES_FOR_LAYOUT, obj)
|
46
|
+
else
|
47
|
+
raise "do not know how to check outdatedness of #{obj.inspect}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
memoize :outdatedness_status_for
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
contract C::ArrayOf[Class], C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout], OutdatednessStatus => C::Maybe[OutdatednessStatus]
|
55
|
+
def apply_rules(rules, obj, status = OutdatednessStatus.new)
|
56
|
+
rules.inject(status) do |acc, rule|
|
57
|
+
if !acc.useful_to_apply?(rule)
|
58
|
+
acc
|
59
|
+
elsif rule.instance.apply(obj, @outdatedness_checker)
|
60
|
+
acc.update(rule.instance.reason)
|
61
|
+
else
|
62
|
+
acc
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
contract C::ArrayOf[Class], C::ArrayOf[C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout]] => C::Maybe[OutdatednessStatus]
|
68
|
+
def apply_rules_multi(rules, objs)
|
69
|
+
objs.inject(OutdatednessStatus.new) { |acc, elem| apply_rules(rules, elem, acc) }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
6
73
|
extend Nanoc::Int::Memoization
|
7
74
|
|
8
75
|
include Nanoc::Int::ContractsSupport
|
@@ -10,6 +77,7 @@ module Nanoc::Int
|
|
10
77
|
attr_reader :checksum_store
|
11
78
|
attr_reader :dependency_store
|
12
79
|
attr_reader :rule_memory_store
|
80
|
+
attr_reader :action_provider
|
13
81
|
attr_reader :site
|
14
82
|
|
15
83
|
Reasons = Nanoc::Int::OutdatednessReasons
|
@@ -28,8 +96,6 @@ module Nanoc::Int
|
|
28
96
|
@action_provider = action_provider
|
29
97
|
@reps = reps
|
30
98
|
|
31
|
-
@basic_outdatedness_reasons = {}
|
32
|
-
@outdatedness_reasons = {}
|
33
99
|
@objects_outdated_due_to_dependencies = {}
|
34
100
|
end
|
35
101
|
|
@@ -64,87 +130,18 @@ module Nanoc::Int
|
|
64
130
|
|
65
131
|
private
|
66
132
|
|
67
|
-
contract C::
|
68
|
-
|
69
|
-
|
70
|
-
# {#outdated?} if you want to include dependencies in the outdatedness
|
71
|
-
# check.
|
72
|
-
#
|
73
|
-
# @param [Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] obj The object
|
74
|
-
# whose outdatedness should be checked.
|
75
|
-
#
|
76
|
-
# @return [Boolean] true if the object is outdated, false otherwise
|
77
|
-
def basic_outdated?(obj)
|
78
|
-
!basic_outdatedness_reason_for(obj).nil?
|
133
|
+
contract C::None => Basic
|
134
|
+
def basic
|
135
|
+
@_basic ||= Basic.new(outdatedness_checker: self, reps: @reps)
|
79
136
|
end
|
80
137
|
|
81
138
|
contract C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] => C::Maybe[Reasons::Generic]
|
82
|
-
# Calculates the reason why the given object is outdated. This method does
|
83
|
-
# not take dependencies into account; use {#outdatedness_reason_for?} if
|
84
|
-
# you want to include dependencies in the outdatedness check.
|
85
|
-
#
|
86
|
-
# @param [Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] obj The object
|
87
|
-
# whose outdatedness reason should be calculated.
|
88
|
-
#
|
89
|
-
# @return [Reasons::Generic, nil] The reason why the
|
90
|
-
# given object is outdated, or nil if the object is not outdated.
|
91
139
|
def basic_outdatedness_reason_for(obj)
|
92
|
-
|
93
|
-
|
94
|
-
# Outdated if rules outdated
|
95
|
-
return Reasons::RulesModified if
|
96
|
-
rule_memory_differs_for(obj)
|
97
|
-
|
98
|
-
# Outdated if checksums are missing or different
|
99
|
-
return Reasons::NotEnoughData unless checksums_available?(obj.item)
|
100
|
-
return Reasons::ContentModified unless content_checksums_identical?(obj.item)
|
101
|
-
return Reasons::AttributesModified unless attributes_checksums_identical?(obj.item)
|
102
|
-
|
103
|
-
# Outdated if compiled file doesn't exist (yet)
|
104
|
-
return Reasons::NotWritten if obj.raw_path && !File.file?(obj.raw_path)
|
105
|
-
|
106
|
-
# Outdated if code snippets outdated
|
107
|
-
return Reasons::CodeSnippetsModified if site.code_snippets.any? do |cs|
|
108
|
-
object_modified?(cs)
|
109
|
-
end
|
110
|
-
|
111
|
-
# Outdated if configuration outdated
|
112
|
-
return Reasons::ConfigurationModified if object_modified?(site.config)
|
113
|
-
|
114
|
-
# Not outdated
|
115
|
-
nil
|
116
|
-
when Nanoc::Int::Item
|
117
|
-
@reps[obj].lazy.map { |rep| basic_outdatedness_reason_for(rep) }.find { |s| s }
|
118
|
-
when Nanoc::Int::Layout
|
119
|
-
# Outdated if rules outdated
|
120
|
-
return Reasons::RulesModified if
|
121
|
-
rule_memory_differs_for(obj)
|
122
|
-
|
123
|
-
# Outdated if checksums are missing or different
|
124
|
-
return Reasons::NotEnoughData unless checksums_available?(obj)
|
125
|
-
return Reasons::ContentModified unless content_checksums_identical?(obj)
|
126
|
-
return Reasons::AttributesModified unless attributes_checksums_identical?(obj)
|
127
|
-
|
128
|
-
# Not outdated
|
129
|
-
nil
|
130
|
-
else
|
131
|
-
raise "do not know how to check outdatedness of #{obj.inspect}"
|
132
|
-
end
|
140
|
+
# FIXME: Stop using this; it is no longer accurate, as there can be >1 reasons
|
141
|
+
basic.outdatedness_status_for(obj).reasons.first
|
133
142
|
end
|
134
|
-
memoize :basic_outdatedness_reason_for
|
135
143
|
|
136
144
|
contract C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout], Hamster::Set => C::Bool
|
137
|
-
# Checks whether the given object is outdated due to dependencies.
|
138
|
-
#
|
139
|
-
# @param [Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] obj The object
|
140
|
-
# whose outdatedness should be checked.
|
141
|
-
#
|
142
|
-
# @param [Set] processed The collection of items that has been visited
|
143
|
-
# during this outdatedness check. This is used to prevent checks for
|
144
|
-
# items that (indirectly) depend on their own from looping
|
145
|
-
# indefinitely. It should not be necessary to pass this a custom value.
|
146
|
-
#
|
147
|
-
# @return [Boolean] true if the object is outdated, false otherwise
|
148
145
|
def outdated_due_to_dependencies?(obj, processed = Hamster::Set.new)
|
149
146
|
# Convert from rep to item if necessary
|
150
147
|
obj = obj.item if obj.is_a?(Nanoc::Int::ItemRep)
|
@@ -160,8 +157,10 @@ module Nanoc::Int
|
|
160
157
|
return false if processed.include?(obj)
|
161
158
|
|
162
159
|
# Calculate
|
163
|
-
is_outdated = dependency_store.
|
164
|
-
|
160
|
+
is_outdated = dependency_store.dependencies_causing_outdatedness_of(obj).any? do |dep|
|
161
|
+
dependency_causes_outdatedness?(dep) ||
|
162
|
+
(dep.props.compiled_content? &&
|
163
|
+
outdated_due_to_dependencies?(dep.from, processed.merge([obj])))
|
165
164
|
end
|
166
165
|
|
167
166
|
# Cache
|
@@ -171,66 +170,12 @@ module Nanoc::Int
|
|
171
170
|
is_outdated
|
172
171
|
end
|
173
172
|
|
174
|
-
contract
|
175
|
-
|
176
|
-
|
177
|
-
#
|
178
|
-
# @return [Boolean] true if the rule memory for the given item
|
179
|
-
# represenation has changed, false otherwise
|
180
|
-
def rule_memory_differs_for(obj)
|
181
|
-
!rule_memory_store[obj].eql?(@action_provider.memory_for(obj).serialize)
|
182
|
-
end
|
183
|
-
memoize :rule_memory_differs_for
|
184
|
-
|
185
|
-
contract C::Any => String
|
186
|
-
# @param obj The object to create a checksum for
|
187
|
-
#
|
188
|
-
# @return [String] The digest
|
189
|
-
def calc_checksum(obj)
|
190
|
-
Nanoc::Int::Checksummer.calc(obj)
|
191
|
-
end
|
192
|
-
memoize :calc_checksum
|
193
|
-
|
194
|
-
contract C::Any => C::Bool
|
195
|
-
# @param obj
|
196
|
-
#
|
197
|
-
# @return [Boolean] false if either the new or the old checksum for the
|
198
|
-
# given object is not available, true if both checksums are available
|
199
|
-
def checksums_available?(obj)
|
200
|
-
checksum_store[obj] && calc_checksum(obj) ? true : false
|
201
|
-
end
|
202
|
-
memoize :checksums_available?
|
203
|
-
|
204
|
-
contract C::Any => C::Bool
|
205
|
-
# @param obj
|
206
|
-
#
|
207
|
-
# @return [Boolean] false if the old and new checksums for the given
|
208
|
-
# object differ, true if they are identical
|
209
|
-
def checksums_identical?(obj)
|
210
|
-
checksum_store[obj] == calc_checksum(obj)
|
211
|
-
end
|
212
|
-
memoize :checksums_identical?
|
213
|
-
|
214
|
-
contract C::Or[Nanoc::Int::Item, Nanoc::Int::Layout] => C::Bool
|
215
|
-
def content_checksums_identical?(obj)
|
216
|
-
checksum_store.content_checksum_for(obj) == Nanoc::Int::Checksummer.calc_for_content_of(obj)
|
217
|
-
end
|
218
|
-
memoize :content_checksums_identical?
|
219
|
-
|
220
|
-
contract C::Or[Nanoc::Int::Item, Nanoc::Int::Layout] => C::Bool
|
221
|
-
def attributes_checksums_identical?(obj)
|
222
|
-
checksum_store.attributes_checksum_for(obj) == Nanoc::Int::Checksummer.calc_for_attributes_of(obj)
|
223
|
-
end
|
224
|
-
memoize :attributes_checksums_identical?
|
173
|
+
contract Nanoc::Int::Dependency => C::Bool
|
174
|
+
def dependency_causes_outdatedness?(dependency)
|
175
|
+
return true if dependency.from.nil?
|
225
176
|
|
226
|
-
|
227
|
-
|
228
|
-
#
|
229
|
-
# @return [Boolean] true if the old and new checksums for the given object
|
230
|
-
# are available and identical, false otherwise
|
231
|
-
def object_modified?(obj)
|
232
|
-
!checksums_available?(obj) || !checksums_identical?(obj)
|
177
|
+
status = basic.outdatedness_status_for(dependency.from)
|
178
|
+
(status.props.active & dependency.props.active).any?
|
233
179
|
end
|
234
|
-
memoize :object_modified?
|
235
180
|
end
|
236
181
|
end
|
@@ -9,43 +9,54 @@ module Nanoc::Int
|
|
9
9
|
# @return [String] A descriptive message for this outdatedness reason
|
10
10
|
attr_reader :message
|
11
11
|
|
12
|
+
# @return [Nanoc::Int::Props]
|
13
|
+
attr_reader :props
|
14
|
+
|
12
15
|
# @param [String] message The descriptive message for this outdatedness
|
13
16
|
# reason
|
14
|
-
def initialize(message)
|
17
|
+
def initialize(message, props = Nanoc::Int::Props.new)
|
15
18
|
@message = message
|
19
|
+
@props = props
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
19
23
|
CodeSnippetsModified = Generic.new(
|
20
24
|
'The code snippets have been modified since the last time the site was compiled.',
|
25
|
+
Props.new(raw_content: true, attributes: true, compiled_content: true, path: true),
|
21
26
|
)
|
22
27
|
|
23
28
|
ConfigurationModified = Generic.new(
|
24
29
|
'The site configuration has been modified since the last time the site was compiled.',
|
30
|
+
Props.new(raw_content: true, attributes: true, compiled_content: true, path: true),
|
25
31
|
)
|
26
32
|
|
27
33
|
DependenciesOutdated = Generic.new(
|
28
34
|
'This item uses content or attributes that have changed since the last time the site was compiled.',
|
29
35
|
)
|
30
36
|
|
31
|
-
NotEnoughData = Generic.new(
|
32
|
-
'Not enough data is present to correctly determine whether the item is outdated.',
|
33
|
-
)
|
34
|
-
|
35
37
|
NotWritten = Generic.new(
|
36
38
|
'This item representation has not yet been written to the output directory (but it does have a path).',
|
39
|
+
Props.new(raw_content: true, attributes: true, compiled_content: true, path: true),
|
37
40
|
)
|
38
41
|
|
39
42
|
RulesModified = Generic.new(
|
40
43
|
'The rules file has been modified since the last time the site was compiled.',
|
44
|
+
Props.new(compiled_content: true, path: true),
|
41
45
|
)
|
42
46
|
|
43
47
|
ContentModified = Generic.new(
|
44
48
|
'The content of this item has been modified since the last time the site was compiled.',
|
49
|
+
Props.new(raw_content: true, compiled_content: true),
|
45
50
|
)
|
46
51
|
|
47
52
|
AttributesModified = Generic.new(
|
48
53
|
'The attributes of this item have been modified since the last time the site was compiled.',
|
54
|
+
Props.new(attributes: true, compiled_content: true),
|
55
|
+
)
|
56
|
+
|
57
|
+
PathsModified = Generic.new(
|
58
|
+
'One or more output paths of this item have been modified since the last time the site was compiled.',
|
59
|
+
Props.new(path: true),
|
49
60
|
)
|
50
61
|
end
|
51
62
|
end
|
data/lib/nanoc/base/entities.rb
CHANGED
@@ -15,6 +15,10 @@ require_relative 'entities/item'
|
|
15
15
|
require_relative 'entities/item_rep'
|
16
16
|
require_relative 'entities/layout'
|
17
17
|
require_relative 'entities/pattern'
|
18
|
+
require_relative 'entities/props'
|
18
19
|
require_relative 'entities/rule_memory'
|
19
20
|
require_relative 'entities/site'
|
20
21
|
require_relative 'entities/snapshot_def'
|
22
|
+
|
23
|
+
require_relative 'entities/outdatedness_status'
|
24
|
+
require_relative 'entities/dependency'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Nanoc::Int
|
2
|
+
# @api private
|
3
|
+
# A dependency between two items/layouts.
|
4
|
+
class Dependency
|
5
|
+
include Nanoc::Int::ContractsSupport
|
6
|
+
|
7
|
+
contract C::None => C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]]
|
8
|
+
attr_reader :from
|
9
|
+
|
10
|
+
contract C::None => C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]]
|
11
|
+
attr_reader :to
|
12
|
+
|
13
|
+
contract C::None => Nanoc::Int::Props
|
14
|
+
attr_reader :props
|
15
|
+
|
16
|
+
contract C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]], C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]], Nanoc::Int::Props => C::Any
|
17
|
+
def initialize(from, to, props)
|
18
|
+
@from = from
|
19
|
+
@to = to
|
20
|
+
@props = props
|
21
|
+
end
|
22
|
+
|
23
|
+
contract C::None => String
|
24
|
+
def inspect
|
25
|
+
"Dependency(#{@from.inspect} -> #{@to.inspect}, #{@props.inspect})"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Nanoc::Int
|
2
|
+
# @api private
|
3
|
+
class OutdatednessStatus
|
4
|
+
attr_reader :reasons
|
5
|
+
attr_reader :props
|
6
|
+
|
7
|
+
def initialize(reasons: [], props: Props.new)
|
8
|
+
@reasons = reasons
|
9
|
+
@props = props
|
10
|
+
end
|
11
|
+
|
12
|
+
def useful_to_apply?(rule)
|
13
|
+
(rule.instance.reason.props.active - @props.active).any?
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(reason)
|
17
|
+
self.class.new(
|
18
|
+
reasons: @reasons + [reason],
|
19
|
+
props: @props.merge(reason.props),
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Nanoc::Int
|
2
|
+
# @api private
|
3
|
+
class Props
|
4
|
+
include Nanoc::Int::ContractsSupport
|
5
|
+
|
6
|
+
contract C::KeywordArgs[raw_content: C::Optional[C::Bool], attributes: C::Optional[C::Bool], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]] => C::Any
|
7
|
+
def initialize(raw_content: false, attributes: false, compiled_content: false, path: false)
|
8
|
+
@raw_content = raw_content
|
9
|
+
@attributes = attributes
|
10
|
+
@compiled_content = compiled_content
|
11
|
+
@path = path
|
12
|
+
end
|
13
|
+
|
14
|
+
contract C::None => String
|
15
|
+
def inspect
|
16
|
+
''.tap do |s|
|
17
|
+
s << 'Props('
|
18
|
+
s << (raw_content? ? 'r' : '_')
|
19
|
+
s << (attributes? ? 'a' : '_')
|
20
|
+
s << (compiled_content? ? 'c' : '_')
|
21
|
+
s << (path? ? 'p' : '_')
|
22
|
+
s << ')'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
contract C::None => C::Bool
|
27
|
+
def raw_content?
|
28
|
+
@raw_content
|
29
|
+
end
|
30
|
+
|
31
|
+
contract C::None => C::Bool
|
32
|
+
def attributes?
|
33
|
+
@attributes
|
34
|
+
end
|
35
|
+
|
36
|
+
contract C::None => C::Bool
|
37
|
+
def compiled_content?
|
38
|
+
@compiled_content
|
39
|
+
end
|
40
|
+
|
41
|
+
contract C::None => C::Bool
|
42
|
+
def path?
|
43
|
+
@path
|
44
|
+
end
|
45
|
+
|
46
|
+
contract Nanoc::Int::Props => Nanoc::Int::Props
|
47
|
+
def merge(other)
|
48
|
+
Props.new(
|
49
|
+
raw_content: raw_content? || other.raw_content?,
|
50
|
+
attributes: attributes? || other.attributes?,
|
51
|
+
compiled_content: compiled_content? || other.compiled_content?,
|
52
|
+
path: path? || other.path?,
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
contract C::None => Set
|
57
|
+
def active
|
58
|
+
Set.new.tap do |pr|
|
59
|
+
pr << :raw_content if raw_content?
|
60
|
+
pr << :attributes if attributes?
|
61
|
+
pr << :compiled_content if compiled_content?
|
62
|
+
pr << :path if path?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
contract C::None => Hash
|
67
|
+
def to_h
|
68
|
+
{
|
69
|
+
raw_content: raw_content?,
|
70
|
+
attributes: attributes?,
|
71
|
+
compiled_content: compiled_content?,
|
72
|
+
path: path?,
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -47,6 +47,13 @@ module Nanoc::Int
|
|
47
47
|
@actions.any? { |a| a.is_a?(Nanoc::Int::ProcessingActions::Layout) }
|
48
48
|
end
|
49
49
|
|
50
|
+
contract C::None => Hash
|
51
|
+
def paths
|
52
|
+
snapshot_actions.each_with_object({}) do |action, paths|
|
53
|
+
paths[action.snapshot_name] = action.path
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
50
57
|
# TODO: Add contract
|
51
58
|
def serialize
|
52
59
|
map(&:serialize)
|
@@ -1,48 +1,6 @@
|
|
1
1
|
module Nanoc::Int
|
2
2
|
# @api private
|
3
3
|
class DependencyStore < ::Nanoc::Int::Store
|
4
|
-
# A dependency between two items/layouts.
|
5
|
-
class Dependency
|
6
|
-
include Nanoc::Int::ContractsSupport
|
7
|
-
|
8
|
-
contract C::None => C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]
|
9
|
-
attr_reader :from
|
10
|
-
|
11
|
-
contract C::None => C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]
|
12
|
-
attr_reader :to
|
13
|
-
|
14
|
-
contract C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]], C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]], C::KeywordArgs[raw_content: C::Optional[C::Bool], attributes: C::Optional[C::Bool], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]] => C::Any
|
15
|
-
def initialize(from, to, raw_content:, attributes:, compiled_content:, path:)
|
16
|
-
@from = from
|
17
|
-
@to = to
|
18
|
-
|
19
|
-
@raw_content = raw_content
|
20
|
-
@attributes = attributes
|
21
|
-
@compiled_content = compiled_content
|
22
|
-
@path = path
|
23
|
-
end
|
24
|
-
|
25
|
-
contract C::None => C::Bool
|
26
|
-
def raw_content?
|
27
|
-
@raw_content
|
28
|
-
end
|
29
|
-
|
30
|
-
contract C::None => C::Bool
|
31
|
-
def attributes?
|
32
|
-
@attributes
|
33
|
-
end
|
34
|
-
|
35
|
-
contract C::None => C::Bool
|
36
|
-
def compiled_content?
|
37
|
-
@compiled_content
|
38
|
-
end
|
39
|
-
|
40
|
-
contract C::None => C::Bool
|
41
|
-
def path?
|
42
|
-
@path
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
4
|
include Nanoc::Int::ContractsSupport
|
47
5
|
|
48
6
|
# @return [Array<Nanoc::Int::Item, Nanoc::Int::Layout>]
|
@@ -56,18 +14,20 @@ module Nanoc::Int
|
|
56
14
|
@graph = Nanoc::Int::DirectedGraph.new([nil] + @objects)
|
57
15
|
end
|
58
16
|
|
59
|
-
contract C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] => C::ArrayOf[Dependency]
|
17
|
+
contract C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] => C::ArrayOf[Nanoc::Int::Dependency]
|
60
18
|
def dependencies_causing_outdatedness_of(object)
|
61
19
|
objects_causing_outdatedness_of(object).map do |other_object|
|
62
|
-
props =
|
20
|
+
props = props_for(other_object, object)
|
63
21
|
|
64
|
-
Dependency.new(
|
22
|
+
Nanoc::Int::Dependency.new(
|
65
23
|
other_object,
|
66
24
|
object,
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
25
|
+
Nanoc::Int::Props.new(
|
26
|
+
raw_content: props.fetch(:raw_content, false),
|
27
|
+
attributes: props.fetch(:attributes, false),
|
28
|
+
compiled_content: props.fetch(:compiled_content, false),
|
29
|
+
path: props.fetch(:path, false),
|
30
|
+
),
|
71
31
|
)
|
72
32
|
end
|
73
33
|
end
|
@@ -123,12 +83,12 @@ module Nanoc::Int
|
|
123
83
|
#
|
124
84
|
# @return [void]
|
125
85
|
def record_dependency(src, dst, raw_content: false, attributes: false, compiled_content: false, path: false)
|
126
|
-
existing_props = @graph.props_for(dst, src) || {}
|
127
|
-
new_props =
|
128
|
-
props =
|
86
|
+
existing_props = Nanoc::Int::Props.new(@graph.props_for(dst, src) || {})
|
87
|
+
new_props = Nanoc::Int::Props.new(raw_content: raw_content, attributes: attributes, compiled_content: compiled_content, path: path)
|
88
|
+
props = existing_props.merge(new_props)
|
129
89
|
|
130
90
|
# Warning! dst and src are *reversed* here!
|
131
|
-
@graph.add_edge(dst, src, props: props) unless src == dst
|
91
|
+
@graph.add_edge(dst, src, props: props.to_h) unless src == dst
|
132
92
|
end
|
133
93
|
|
134
94
|
# Empties the list of dependencies for the given object. This is necessary
|
@@ -146,10 +106,13 @@ module Nanoc::Int
|
|
146
106
|
|
147
107
|
protected
|
148
108
|
|
149
|
-
def
|
150
|
-
|
151
|
-
|
152
|
-
|
109
|
+
def props_for(a, b)
|
110
|
+
props = @graph.props_for(a, b) || {}
|
111
|
+
|
112
|
+
if props.values.any? { |v| v }
|
113
|
+
props
|
114
|
+
else
|
115
|
+
{ raw_content: true, attributes: true, compiled_content: true, path: true }
|
153
116
|
end
|
154
117
|
end
|
155
118
|
|
@@ -179,10 +142,11 @@ module Nanoc::Int
|
|
179
142
|
|
180
143
|
# Record dependency from all items on new items
|
181
144
|
new_objects = (@objects - previous_objects)
|
145
|
+
new_props = { raw_content: true, attributes: true, compiled_content: true, path: true }
|
182
146
|
new_objects.each do |new_obj|
|
183
147
|
@objects.each do |obj|
|
184
148
|
next unless obj.is_a?(Nanoc::Int::Item)
|
185
|
-
@graph.add_edge(new_obj, obj)
|
149
|
+
@graph.add_edge(new_obj, obj, props: new_props)
|
186
150
|
end
|
187
151
|
end
|
188
152
|
end
|
data/lib/nanoc/base/services.rb
CHANGED
@@ -11,3 +11,5 @@ require_relative 'services/item_rep_writer'
|
|
11
11
|
require_relative 'services/notification_center'
|
12
12
|
require_relative 'services/pruner'
|
13
13
|
require_relative 'services/temp_filename_factory'
|
14
|
+
require_relative 'services/outdatedness_rule'
|
15
|
+
require_relative 'services/outdatedness_rules'
|
@@ -129,7 +129,7 @@ module Nanoc
|
|
129
129
|
# Sets up the filter and runs the filter. This method passes its arguments
|
130
130
|
# to {#run} unchanged and returns the return value from {#run}.
|
131
131
|
#
|
132
|
-
# @see
|
132
|
+
# @see #run
|
133
133
|
#
|
134
134
|
# @api private
|
135
135
|
def setup_and_run(*args)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Nanoc::Int
|
2
|
+
# @api private
|
3
|
+
class OutdatednessRule
|
4
|
+
include Nanoc::Int::ContractsSupport
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def apply(_obj, _outdatedness_checker)
|
8
|
+
raise NotImplementedError.new('Nanoc::Int::OutdatednessRule subclasses must implement ##reason, and #apply')
|
9
|
+
end
|
10
|
+
|
11
|
+
contract C::None => String
|
12
|
+
def inspect
|
13
|
+
"#{self.class.name}(#{reason})"
|
14
|
+
end
|
15
|
+
|
16
|
+
# TODO: remove
|
17
|
+
def reason
|
18
|
+
raise NotImplementedError.new('Nanoc::Int::OutdatednessRule subclasses must implement ##reason, and #apply')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Nanoc::Int
|
2
|
+
# @api private
|
3
|
+
module OutdatednessRules
|
4
|
+
class CodeSnippetsModified < OutdatednessRule
|
5
|
+
extend Nanoc::Int::Memoization
|
6
|
+
|
7
|
+
include Nanoc::Int::ContractsSupport
|
8
|
+
|
9
|
+
def reason
|
10
|
+
Nanoc::Int::OutdatednessReasons::CodeSnippetsModified
|
11
|
+
end
|
12
|
+
|
13
|
+
def apply(_obj, outdatedness_checker)
|
14
|
+
any_snippets_modified?(outdatedness_checker)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def any_snippets_modified?(outdatedness_checker)
|
20
|
+
outdatedness_checker.site.code_snippets.any? do |cs|
|
21
|
+
ch_old = outdatedness_checker.checksum_store[cs]
|
22
|
+
ch_new = Nanoc::Int::Checksummer.calc(cs)
|
23
|
+
ch_old != ch_new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
memoize :any_snippets_modified?
|
27
|
+
end
|
28
|
+
|
29
|
+
class ConfigurationModified < OutdatednessRule
|
30
|
+
extend Nanoc::Int::Memoization
|
31
|
+
|
32
|
+
def reason
|
33
|
+
Nanoc::Int::OutdatednessReasons::ConfigurationModified
|
34
|
+
end
|
35
|
+
|
36
|
+
def apply(_obj, outdatedness_checker)
|
37
|
+
config_modified?(outdatedness_checker)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def config_modified?(outdatedness_checker)
|
43
|
+
obj = outdatedness_checker.site.config
|
44
|
+
ch_old = outdatedness_checker.checksum_store[obj]
|
45
|
+
ch_new = Nanoc::Int::Checksummer.calc(obj)
|
46
|
+
ch_old != ch_new
|
47
|
+
end
|
48
|
+
memoize :config_modified?
|
49
|
+
end
|
50
|
+
|
51
|
+
class NotWritten < OutdatednessRule
|
52
|
+
def reason
|
53
|
+
Nanoc::Int::OutdatednessReasons::NotWritten
|
54
|
+
end
|
55
|
+
|
56
|
+
def apply(obj, _outdatedness_checker)
|
57
|
+
# FIXME: check all paths (for all snapshots)
|
58
|
+
obj.raw_path && !File.file?(obj.raw_path)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class ContentModified < OutdatednessRule
|
63
|
+
def reason
|
64
|
+
Nanoc::Int::OutdatednessReasons::ContentModified
|
65
|
+
end
|
66
|
+
|
67
|
+
def apply(obj, outdatedness_checker)
|
68
|
+
obj = obj.item if obj.is_a?(Nanoc::Int::ItemRep)
|
69
|
+
|
70
|
+
ch_old = outdatedness_checker.checksum_store.content_checksum_for(obj)
|
71
|
+
ch_new = Nanoc::Int::Checksummer.calc_for_content_of(obj)
|
72
|
+
ch_old != ch_new
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class AttributesModified < OutdatednessRule
|
77
|
+
def reason
|
78
|
+
Nanoc::Int::OutdatednessReasons::AttributesModified
|
79
|
+
end
|
80
|
+
|
81
|
+
def apply(obj, outdatedness_checker)
|
82
|
+
obj = obj.item if obj.is_a?(Nanoc::Int::ItemRep)
|
83
|
+
|
84
|
+
ch_old = outdatedness_checker.checksum_store.attributes_checksum_for(obj)
|
85
|
+
ch_new = Nanoc::Int::Checksummer.calc_for_attributes_of(obj)
|
86
|
+
ch_old != ch_new
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class RulesModified < OutdatednessRule
|
91
|
+
def reason
|
92
|
+
Nanoc::Int::OutdatednessReasons::RulesModified
|
93
|
+
end
|
94
|
+
|
95
|
+
def apply(obj, outdatedness_checker)
|
96
|
+
mem_old = outdatedness_checker.rule_memory_store[obj]
|
97
|
+
mem_new = outdatedness_checker.action_provider.memory_for(obj).serialize
|
98
|
+
!mem_old.eql?(mem_new)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class PathsModified < OutdatednessRule
|
103
|
+
def reason
|
104
|
+
Nanoc::Int::OutdatednessReasons::PathsModified
|
105
|
+
end
|
106
|
+
|
107
|
+
def apply(obj, outdatedness_checker)
|
108
|
+
# FIXME: Prefer to not work on serialised version
|
109
|
+
|
110
|
+
mem_old = outdatedness_checker.rule_memory_store[obj]
|
111
|
+
mem_new = outdatedness_checker.action_provider.memory_for(obj).serialize
|
112
|
+
return true if mem_old.nil?
|
113
|
+
|
114
|
+
paths_old = mem_old.select { |pa| pa[0] == :snapshot }
|
115
|
+
paths_new = mem_new.select { |pa| pa[0] == :snapshot }
|
116
|
+
|
117
|
+
paths_old != paths_new
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -90,10 +90,10 @@ module Nanoc::CLI::Commands
|
|
90
90
|
end
|
91
91
|
|
92
92
|
props = ''
|
93
|
-
props << (dep.raw_content? ? 'r' : '_')
|
94
|
-
props << (dep.attributes? ? 'a' : '_')
|
95
|
-
props << (dep.compiled_content? ? 'c' : '_')
|
96
|
-
props << (dep.path? ? 'p' : '_')
|
93
|
+
props << (dep.props.raw_content? ? 'r' : '_')
|
94
|
+
props << (dep.props.attributes? ? 'a' : '_')
|
95
|
+
props << (dep.props.compiled_content? ? 'c' : '_')
|
96
|
+
props << (dep.props.path? ? 'p' : '_')
|
97
97
|
|
98
98
|
if pred
|
99
99
|
puts " [ #{format '%6s', type} ] (#{props}) #{pred.identifier}"
|
@@ -47,7 +47,6 @@ module Nanoc::RuleDSL
|
|
47
47
|
raise UnsupportedObjectTypeException.new(obj)
|
48
48
|
end
|
49
49
|
end
|
50
|
-
memoize :[]
|
51
50
|
|
52
51
|
# @param [Nanoc::Int::ItemRep] rep The item representation for which to fetch
|
53
52
|
# the list of snapshots
|
@@ -89,17 +88,6 @@ module Nanoc::RuleDSL
|
|
89
88
|
executor.rule_memory
|
90
89
|
end
|
91
90
|
|
92
|
-
# @param [Nanoc::Int::ItemRep] rep The item representation to get the rule
|
93
|
-
# memory for
|
94
|
-
#
|
95
|
-
# @return [Hash<Symbol, String>] Pairs of snapshot name and path
|
96
|
-
def paths_for_rep(rep)
|
97
|
-
snapshot_actions = new_rule_memory_for_rep(rep).snapshot_actions
|
98
|
-
snapshot_actions.each_with_object({}) do |action, paths|
|
99
|
-
paths[action.snapshot_name] = action.path
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
91
|
# @param [Nanoc::Int::Layout] layout
|
104
92
|
#
|
105
93
|
# @return [Nanoc::Int::RuleMemory]
|
data/lib/nanoc/version.rb
CHANGED
@@ -42,7 +42,7 @@ class Nanoc::Int::OutdatednessCheckerTest < Nanoc::TestCase
|
|
42
42
|
site.compiler.load_stores
|
43
43
|
outdatedness_checker = site.compiler.send :outdatedness_checker
|
44
44
|
rep = site.compiler.reps[site.items.find { |i| i.identifier == '/' }][0]
|
45
|
-
assert_equal ::Nanoc::Int::OutdatednessReasons::
|
45
|
+
assert_equal ::Nanoc::Int::OutdatednessReasons::ContentModified, outdatedness_checker.outdatedness_reason_for(rep)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -2,7 +2,7 @@ class Nanoc::Checking::Checks::HTMLTest < Nanoc::TestCase
|
|
2
2
|
def test_run_ok
|
3
3
|
require 'w3c_validators'
|
4
4
|
|
5
|
-
if ::W3CValidators::VERSION
|
5
|
+
if ::W3CValidators::VERSION =~ /\A1\.3|1\.3\.1\z/
|
6
6
|
skip 'broken (see https://github.com/w3c-validators/w3c_validators/issues/25)'
|
7
7
|
end
|
8
8
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nanoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.4.
|
4
|
+
version: 4.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Defreyne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cri
|
@@ -138,6 +138,7 @@ files:
|
|
138
138
|
- lib/nanoc/base/entities/configuration.rb
|
139
139
|
- lib/nanoc/base/entities/content.rb
|
140
140
|
- lib/nanoc/base/entities/context.rb
|
141
|
+
- lib/nanoc/base/entities/dependency.rb
|
141
142
|
- lib/nanoc/base/entities/directed_graph.rb
|
142
143
|
- lib/nanoc/base/entities/document.rb
|
143
144
|
- lib/nanoc/base/entities/identifiable_collection.rb
|
@@ -146,12 +147,14 @@ files:
|
|
146
147
|
- lib/nanoc/base/entities/item_rep.rb
|
147
148
|
- lib/nanoc/base/entities/layout.rb
|
148
149
|
- lib/nanoc/base/entities/lazy_value.rb
|
150
|
+
- lib/nanoc/base/entities/outdatedness_status.rb
|
149
151
|
- lib/nanoc/base/entities/pattern.rb
|
150
152
|
- lib/nanoc/base/entities/processing_action.rb
|
151
153
|
- lib/nanoc/base/entities/processing_actions.rb
|
152
154
|
- lib/nanoc/base/entities/processing_actions/filter.rb
|
153
155
|
- lib/nanoc/base/entities/processing_actions/layout.rb
|
154
156
|
- lib/nanoc/base/entities/processing_actions/snapshot.rb
|
157
|
+
- lib/nanoc/base/entities/props.rb
|
155
158
|
- lib/nanoc/base/entities/rule_memory.rb
|
156
159
|
- lib/nanoc/base/entities/site.rb
|
157
160
|
- lib/nanoc/base/entities/snapshot_def.rb
|
@@ -182,6 +185,8 @@ files:
|
|
182
185
|
- lib/nanoc/base/services/item_rep_selector.rb
|
183
186
|
- lib/nanoc/base/services/item_rep_writer.rb
|
184
187
|
- lib/nanoc/base/services/notification_center.rb
|
188
|
+
- lib/nanoc/base/services/outdatedness_rule.rb
|
189
|
+
- lib/nanoc/base/services/outdatedness_rules.rb
|
185
190
|
- lib/nanoc/base/services/pruner.rb
|
186
191
|
- lib/nanoc/base/services/temp_filename_factory.rb
|
187
192
|
- lib/nanoc/base/views.rb
|