nanoc 4.7.7 → 4.7.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +6 -5
  3. data/NEWS.md +12 -0
  4. data/lib/nanoc/base/entities.rb +1 -0
  5. data/lib/nanoc/base/entities/action_sequence.rb +8 -36
  6. data/lib/nanoc/base/entities/checksum_collection.rb +31 -0
  7. data/lib/nanoc/base/entities/directed_graph.rb +35 -11
  8. data/lib/nanoc/base/errors.rb +3 -1
  9. data/lib/nanoc/base/repos/checksum_store.rb +1 -0
  10. data/lib/nanoc/base/services.rb +1 -0
  11. data/lib/nanoc/base/services/action_sequence_builder.rb +45 -0
  12. data/lib/nanoc/base/services/compiler.rb +34 -14
  13. data/lib/nanoc/base/services/compiler/stages.rb +1 -0
  14. data/lib/nanoc/base/services/compiler/stages/calculate_checksums.rb +31 -0
  15. data/lib/nanoc/base/services/compiler/stages/store_pre_compilation_state.rb +6 -13
  16. data/lib/nanoc/base/services/outdatedness_checker.rb +4 -2
  17. data/lib/nanoc/base/services/outdatedness_rules/attributes_modified.rb +1 -1
  18. data/lib/nanoc/base/services/outdatedness_rules/code_snippets_modified.rb +1 -1
  19. data/lib/nanoc/base/services/outdatedness_rules/configuration_modified.rb +1 -1
  20. data/lib/nanoc/base/services/outdatedness_rules/content_modified.rb +1 -1
  21. data/lib/nanoc/cli/cleaning_stream.rb +1 -1
  22. data/lib/nanoc/cli/commands/show-data.rb +1 -0
  23. data/lib/nanoc/rule_dsl/action_sequence_calculator.rb +7 -14
  24. data/lib/nanoc/rule_dsl/recording_executor.rb +40 -7
  25. data/lib/nanoc/version.rb +1 -1
  26. data/spec/nanoc/base/compiler_spec.rb +5 -5
  27. data/spec/nanoc/base/directed_graph_spec.rb +12 -0
  28. data/spec/nanoc/base/entities/action_sequence_spec.rb +132 -79
  29. data/spec/nanoc/base/errors/dependency_cycle_spec.rb +4 -4
  30. data/spec/nanoc/base/services/compiler/stages/calculate_checksums_spec.rb +69 -0
  31. data/spec/nanoc/base/services/executor_spec.rb +2 -2
  32. data/spec/nanoc/base/services/item_rep_router_spec.rb +4 -4
  33. data/spec/nanoc/base/services/outdatedness_checker_spec.rb +40 -24
  34. data/spec/nanoc/base/services/outdatedness_rules_spec.rb +27 -15
  35. data/spec/nanoc/cli/commands/show_data_spec.rb +2 -0
  36. data/spec/nanoc/rule_dsl/action_sequence_calculator_spec.rb +15 -13
  37. data/spec/nanoc/rule_dsl/recording_executor_spec.rb +4 -3
  38. data/test/cli/test_cleaning_stream.rb +8 -0
  39. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d25ba882d1c709e130d1da34de63b5bee85ffaa2
4
- data.tar.gz: 6e3c673ec2c5b30a25edb775f42197813899cabf
3
+ metadata.gz: bd1bb8411c769f4fece915bf9569b5af2a1a1424
4
+ data.tar.gz: 23b8e4dfd52b52fc012c2ea22d528d294c3971bd
5
5
  SHA512:
6
- metadata.gz: 914fde5a0e842055cabfa804950d3b355f3b03b33b3a72cddbd1654aa4e9233163848386b728e2ce08238de98311d2af31305e874bc421549ac858acb310b73b
7
- data.tar.gz: 2727ef6a9f49eedec58419971d324ce73a50dad71776ff1e303d7a50567b7a47881e4acb8be100cb095bbea68a4a6540da768aedfaaa29f7c05e63fd8732347f
6
+ metadata.gz: 862cb54cefa14a2312bfd417f3d3d744afe2b27740ed57bfb1c2b51c5eaabbe66cdb3130b5b10ea758dea3045a2ac7a6d3fa6caff10c358a76e9af2c1189a8aa
7
+ data.tar.gz: d33204921451b9e6cffa130bbc30fe02e6f1ea88d01854d8c6910d4e07e85fddea6a25448ff84c05bbd6b6407cae2eb7c4a8adbac3c7e4b19a1490a795c12e69
data/Gemfile.lock CHANGED
@@ -1,6 +1,6 @@
1
1
  GIT
2
2
  remote: https://github.com/bbatsov/rubocop.git
3
- revision: dcb3f160a2e23218a7826aadd0e64baefd6d7521
3
+ revision: 9168e82c449bf275b4ce587ac01efff25bf80cc2
4
4
  specs:
5
5
  rubocop (0.48.1)
6
6
  parallel (~> 1.10)
@@ -28,7 +28,7 @@ GEM
28
28
  public_suffix (~> 2.0, >= 2.0.2)
29
29
  adsf (1.2.1)
30
30
  rack (>= 1.0.0)
31
- appraisal (2.1.0)
31
+ appraisal (2.2.0)
32
32
  bundler
33
33
  rake
34
34
  thor (>= 0.14.0)
@@ -163,7 +163,7 @@ GEM
163
163
  fog-profitbricks (3.0.0)
164
164
  fog-core (~> 1.42)
165
165
  fog-json (~> 1.0)
166
- fog-rackspace (0.1.4)
166
+ fog-rackspace (0.1.5)
167
167
  fog-core (>= 1.35)
168
168
  fog-json (>= 1.0)
169
169
  fog-xml (>= 0.1)
@@ -233,7 +233,7 @@ GEM
233
233
  hashdiff (0.3.2)
234
234
  inflecto (0.0.2)
235
235
  ipaddress (0.8.3)
236
- json (2.0.4)
236
+ json (2.1.0)
237
237
  kramdown (1.13.2)
238
238
  less (2.6.0)
239
239
  commonjs (~> 0.2.7)
@@ -281,7 +281,8 @@ GEM
281
281
  pygments.rb (1.1.2)
282
282
  multi_json (>= 1.0.0)
283
283
  rack (2.0.1)
284
- rainbow (2.2.1)
284
+ rainbow (2.2.2)
285
+ rake
285
286
  rainpress (1.0.1)
286
287
  rake (12.0.0)
287
288
  rb-fsevent (0.9.8)
data/NEWS.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Nanoc news
2
2
 
3
+ ## 4.7.8 (2017-04-22)
4
+
5
+ Fixes:
6
+
7
+ * Fixed a crash when printing dependency cycle error messages (#1164, #1166)
8
+ * Fixed incorrect ordering in dependency cycle error messages (#1167, #1168)
9
+ * Fixed a crash when attempting to print malformed UTF-8 strings (#1163, #1165)
10
+
11
+ Enhancements:
12
+
13
+ * Added various speed improvements (#1158, #1159, #1160)
14
+
3
15
  ## 4.7.7 (2017-04-16)
4
16
 
5
17
  Enhancements:
@@ -20,6 +20,7 @@ require_relative 'entities/action_sequence'
20
20
  require_relative 'entities/site'
21
21
  require_relative 'entities/snapshot_def'
22
22
 
23
+ require_relative 'entities/checksum_collection'
23
24
  require_relative 'entities/outdatedness_status'
24
25
  require_relative 'entities/outdatedness_reasons'
25
26
  require_relative 'entities/dependency'
@@ -2,6 +2,7 @@ module Nanoc::Int
2
2
  class ActionSequence
3
3
  include Nanoc::Int::ContractsSupport
4
4
  include Enumerable
5
+ extend Nanoc::Int::Memoization
5
6
 
6
7
  attr_reader :item_rep
7
8
  attr_reader :actions
@@ -11,6 +12,12 @@ module Nanoc::Int
11
12
  @actions = actions
12
13
  end
13
14
 
15
+ def self.build(rep)
16
+ builder = Nanoc::Int::ActionSequenceBuilder.new(rep)
17
+ yield(builder)
18
+ builder.action_sequence
19
+ end
20
+
14
21
  contract C::None => Numeric
15
22
  def size
16
23
  @actions.size
@@ -21,42 +28,18 @@ module Nanoc::Int
21
28
  @actions[idx]
22
29
  end
23
30
 
24
- contract Symbol, Hash => self
25
- def add_filter(filter_name, params)
26
- @actions << Nanoc::Int::ProcessingActions::Filter.new(filter_name, params)
27
- self
28
- end
29
-
30
- contract String, C::Maybe[Hash] => self
31
- def add_layout(layout_identifier, params)
32
- @actions << Nanoc::Int::ProcessingActions::Layout.new(layout_identifier, params)
33
- self
34
- end
35
-
36
- contract Symbol, C::Maybe[String] => self
37
- def add_snapshot(snapshot_name, path)
38
- will_add_snapshot(snapshot_name)
39
- @actions << Nanoc::Int::ProcessingActions::Snapshot.new([snapshot_name], path ? [path] : [])
40
- self
41
- end
42
-
43
31
  contract C::None => C::ArrayOf[Nanoc::Int::ProcessingAction]
44
32
  def snapshot_actions
45
33
  @actions.select { |a| a.is_a?(Nanoc::Int::ProcessingActions::Snapshot) }
46
34
  end
47
35
 
48
- contract C::None => C::Bool
49
- def any_layouts?
50
- @actions.any? { |a| a.is_a?(Nanoc::Int::ProcessingActions::Layout) }
51
- end
52
-
53
36
  contract C::None => Array
54
37
  def paths
55
38
  snapshot_actions.map { |a| [a.snapshot_names, a.paths] }
56
39
  end
57
40
 
58
41
  # TODO: Add contract
59
- def serialize
42
+ memoized def serialize
60
43
  to_a.map(&:serialize)
61
44
  end
62
45
 
@@ -91,16 +74,5 @@ module Nanoc::Int
91
74
 
92
75
  snapshot_defs
93
76
  end
94
-
95
- private
96
-
97
- def will_add_snapshot(name)
98
- @_snapshot_names ||= Set.new
99
- if @_snapshot_names.include?(name)
100
- raise Nanoc::Int::Errors::CannotCreateMultipleSnapshotsWithSameName.new(@item_rep, name)
101
- else
102
- @_snapshot_names << name
103
- end
104
- end
105
77
  end
106
78
  end
@@ -0,0 +1,31 @@
1
+ module Nanoc::Int
2
+ class ChecksumCollection
3
+ include Nanoc::Int::ContractsSupport
4
+ extend Nanoc::Int::Memoization
5
+
6
+ c_obj = C::Or[Nanoc::Int::Item, Nanoc::Int::Layout, Nanoc::Int::Configuration, Nanoc::Int::CodeSnippet]
7
+
8
+ def initialize(checksums)
9
+ @checksums = checksums
10
+ end
11
+
12
+ contract c_obj => C::Maybe[String]
13
+ def checksum_for(obj)
14
+ @checksums[obj.reference]
15
+ end
16
+
17
+ contract c_obj => C::Maybe[String]
18
+ def content_checksum_for(obj)
19
+ @checksums[[obj.reference, :content]]
20
+ end
21
+
22
+ contract c_obj => C::Maybe[C::HashOf[Symbol, String]]
23
+ def attributes_checksum_for(obj)
24
+ @checksums[[obj.reference, :each_attribute]]
25
+ end
26
+
27
+ def to_h
28
+ @checksums
29
+ end
30
+ end
31
+ end
@@ -158,18 +158,42 @@ module Nanoc::Int
158
158
 
159
159
  # @group Querying the graph
160
160
 
161
+ # Returns a cycle if there is any.
161
162
  def any_cycle
162
- path = [@vertices.keys.first]
163
-
164
- loop do
165
- nexts = direct_successors_of(path.last)
166
- cycle_start_index = path.find_index { |node| nexts.include?(node) }
167
- if cycle_start_index
168
- break path[cycle_start_index..-1]
169
- elsif nexts.empty?
170
- break nil
171
- else
172
- path << nexts.sample
163
+ all_paths.lazy.map { |path| cycle_in_path(path) }.find(&:itself)
164
+ end
165
+
166
+ # Given a potentially closed path, returns a cycle if there is any.
167
+ def cycle_in_path(path)
168
+ vertex = path.last
169
+ index = path.index(vertex)
170
+
171
+ if index < path.size - 1
172
+ path[index..-2]
173
+ end
174
+ end
175
+
176
+ # Yields all paths (including potentially closed ones).
177
+ def all_paths
178
+ Enumerator.new do |y|
179
+ @vertices.keys.each do |vertex|
180
+ dfs_from(vertex) do |path|
181
+ y << path
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ # Yields all paths (including potentially closed ones) starting from the given vertex.
188
+ def dfs_from(vertex, path_so_far = [])
189
+ new_path = path_so_far + [vertex]
190
+ yield(new_path)
191
+
192
+ unless path_so_far.include?(vertex)
193
+ direct_successors_of(vertex).each do |next_vertex|
194
+ dfs_from(next_vertex, new_path) do |path|
195
+ yield(path)
196
+ end
173
197
  end
174
198
  end
175
199
  end
@@ -75,7 +75,9 @@ module Nanoc::Int
75
75
  msg_bits = []
76
76
  msg_bits << 'The site cannot be compiled because there is a dependency cycle:'
77
77
  msg_bits << ''
78
- cycle.each.with_index { |r, i| msg_bits << " (#{i + 1}) item #{r.item.identifier}, rep #{r.name.inspect}, depends on" }
78
+ cycle.reverse_each.with_index do |r, i|
79
+ msg_bits << " (#{i + 1}) item #{r.item.identifier}, rep #{r.name.inspect}, uses compiled content of"
80
+ end
79
81
  msg_bits.last << ' (1)'
80
82
 
81
83
  super(msg_bits.map { |x| x + "\n" }.join(''))
@@ -6,6 +6,7 @@ module Nanoc::Int
6
6
  class ChecksumStore < ::Nanoc::Int::Store
7
7
  include Nanoc::Int::ContractsSupport
8
8
 
9
+ attr_writer :checksums
9
10
  attr_accessor :objects
10
11
 
11
12
  c_obj = C::Or[Nanoc::Int::Item, Nanoc::Int::Layout, Nanoc::Int::Configuration, Nanoc::Int::CodeSnippet]
@@ -1,4 +1,5 @@
1
1
  require_relative 'services/action_provider'
2
+ require_relative 'services/action_sequence_builder'
2
3
  require_relative 'services/checksummer'
3
4
  require_relative 'services/compilation_context'
4
5
  require_relative 'services/compiler'
@@ -0,0 +1,45 @@
1
+ module Nanoc::Int
2
+ class ActionSequenceBuilder
3
+ include Nanoc::Int::ContractsSupport
4
+
5
+ def initialize(item_rep)
6
+ @item_rep = item_rep
7
+ @actions = []
8
+ end
9
+
10
+ contract Symbol, Hash => self
11
+ def add_filter(filter_name, params)
12
+ @actions << Nanoc::Int::ProcessingActions::Filter.new(filter_name, params)
13
+ self
14
+ end
15
+
16
+ contract String, C::Maybe[Hash] => self
17
+ def add_layout(layout_identifier, params)
18
+ @actions << Nanoc::Int::ProcessingActions::Layout.new(layout_identifier, params)
19
+ self
20
+ end
21
+
22
+ contract Symbol, C::Maybe[String] => self
23
+ def add_snapshot(snapshot_name, path)
24
+ will_add_snapshot(snapshot_name)
25
+ @actions << Nanoc::Int::ProcessingActions::Snapshot.new([snapshot_name], path ? [path] : [])
26
+ self
27
+ end
28
+
29
+ contract C::None => Nanoc::Int::ActionSequence
30
+ def action_sequence
31
+ Nanoc::Int::ActionSequence.new(@item_rep, actions: @actions)
32
+ end
33
+
34
+ private
35
+
36
+ def will_add_snapshot(name)
37
+ @_snapshot_names ||= Set.new
38
+ if @_snapshot_names.include?(name)
39
+ raise Nanoc::Int::Errors::CannotCreateMultipleSnapshotsWithSameName.new(@item_rep, name)
40
+ else
41
+ @_snapshot_names << name
42
+ end
43
+ end
44
+ end
45
+ end
@@ -51,25 +51,34 @@ module Nanoc::Int
51
51
  dependency_store: @dependency_store,
52
52
  action_sequence_store: @action_sequence_store,
53
53
  action_sequences: @action_sequences,
54
+ checksums: @checksums,
54
55
  reps: reps,
55
56
  )
56
57
  end
57
58
 
58
59
  def run_all
59
- run_stage(preprocess_stage)
60
- @action_sequences = run_stage(build_reps_stage)
60
+ prepare
61
+
62
+ run_stage(forget_outdated_dependencies_stage, @outdated_items)
63
+ run_stage(store_pre_compilation_state_stage(@action_sequences), @checksums)
61
64
  run_stage(prune_stage)
62
- run_stage(load_stores_stage)
63
- outdated_items = run_stage(determine_outdatedness_stage)
64
- run_stage(forget_outdated_dependencies_stage, outdated_items)
65
- run_stage(store_pre_compilation_state_stage)
66
- run_stage(compile_reps_stage)
65
+ run_stage(compile_reps_stage(@action_sequences))
67
66
  run_stage(store_post_compilation_state_stage)
68
67
  run_stage(postprocess_stage)
69
68
  ensure
70
69
  run_stage(cleanup_stage)
71
70
  end
72
71
 
72
+ def prepare
73
+ # FIXME: State is ugly
74
+
75
+ run_stage(preprocess_stage)
76
+ @action_sequences = run_stage(build_reps_stage)
77
+ run_stage(load_stores_stage)
78
+ @checksums = run_stage(calculate_checksums_stage)
79
+ @outdated_items = run_stage(determine_outdatedness_stage)
80
+ end
81
+
73
82
  def compilation_context
74
83
  @_compilation_context ||= Nanoc::Int::CompilationContext.new(
75
84
  action_provider: action_provider,
@@ -90,6 +99,11 @@ module Nanoc::Int
90
99
  @action_sequences = build_reps_stage.run
91
100
  end
92
101
 
102
+ # TODO: remove
103
+ def calculate_checksums
104
+ @checksums = run_stage(calculate_checksums_stage)
105
+ end
106
+
93
107
  private
94
108
 
95
109
  def run_stage(stage, *args)
@@ -133,6 +147,15 @@ module Nanoc::Int
133
147
  )
134
148
  end
135
149
 
150
+ def calculate_checksums_stage
151
+ @_calculate_checksums_stage ||= Stages::CalculateChecksums.new(
152
+ items: @site.items,
153
+ layouts: @site.layouts,
154
+ code_snippets: @site.code_snippets,
155
+ config: @site.config,
156
+ )
157
+ end
158
+
136
159
  def determine_outdatedness_stage
137
160
  @_determine_outdatedness_stage ||= Stages::DetermineOutdatedness.new(
138
161
  reps: reps,
@@ -141,24 +164,21 @@ module Nanoc::Int
141
164
  )
142
165
  end
143
166
 
144
- def store_pre_compilation_state_stage
167
+ def store_pre_compilation_state_stage(action_sequences)
145
168
  @_store_pre_compilation_state_stage ||= Stages::StorePreCompilationState.new(
146
169
  reps: @reps,
147
170
  layouts: site.layouts,
148
- items: site.items,
149
- code_snippets: site.code_snippets,
150
- config: site.config,
151
171
  checksum_store: checksum_store,
152
172
  action_sequence_store: action_sequence_store,
153
- action_sequences: @action_sequences,
173
+ action_sequences: action_sequences,
154
174
  )
155
175
  end
156
176
 
157
- def compile_reps_stage
177
+ def compile_reps_stage(action_sequences)
158
178
  @_compile_reps_stage ||= Stages::CompileReps.new(
159
179
  outdatedness_store: @outdatedness_store,
160
180
  dependency_store: @dependency_store,
161
- action_sequences: @action_sequences,
181
+ action_sequences: action_sequences,
162
182
  compilation_context: compilation_context,
163
183
  compiled_content_cache: compiled_content_cache,
164
184
  )
@@ -1,6 +1,7 @@
1
1
  module Nanoc::Int::Compiler::Stages
2
2
  end
3
3
 
4
+ require_relative 'stages/calculate_checksums'
4
5
  require_relative 'stages/cleanup'
5
6
  require_relative 'stages/compile_reps'
6
7
  require_relative 'stages/determine_outdatedness'
@@ -0,0 +1,31 @@
1
+ module Nanoc::Int::Compiler::Stages
2
+ class CalculateChecksums
3
+ def initialize(items:, layouts:, code_snippets:, config:)
4
+ @items = items
5
+ @layouts = layouts
6
+ @code_snippets = code_snippets
7
+ @config = config
8
+ end
9
+
10
+ def run
11
+ checksums = {}
12
+
13
+ [@items, @layouts].each do |documents|
14
+ documents.each do |document|
15
+ checksums[[document.reference, :content]] =
16
+ Nanoc::Int::Checksummer.calc_for_content_of(document)
17
+ checksums[[document.reference, :each_attribute]] =
18
+ Nanoc::Int::Checksummer.calc_for_each_attribute_of(document)
19
+ end
20
+ end
21
+
22
+ [@items, @layouts, @code_snippets, [@config]].each do |objs|
23
+ objs.each do |obj|
24
+ checksums[obj.reference] = Nanoc::Int::Checksummer.calc(obj)
25
+ end
26
+ end
27
+
28
+ Nanoc::Int::ChecksumCollection.new(checksums)
29
+ end
30
+ end
31
+ end