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