nanoc 4.7.7 → 4.7.8

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.
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