nanoc 3.3.7 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/Gemfile.lock +133 -0
  2. data/NEWS.md +15 -0
  3. data/lib/nanoc.rb +2 -2
  4. data/lib/nanoc/base/compilation/compiler.rb +1 -1
  5. data/lib/nanoc/base/compilation/item_rep_proxy.rb +3 -3
  6. data/lib/nanoc/base/core_ext/string.rb +0 -18
  7. data/lib/nanoc/base/errors.rb +24 -19
  8. data/lib/nanoc/base/plugin_registry.rb +1 -1
  9. data/lib/nanoc/base/result_data/item_rep.rb +1 -2
  10. data/lib/nanoc/base/source_data/site.rb +1 -1
  11. data/lib/nanoc/cli.rb +46 -4
  12. data/lib/nanoc/cli/ansi_string_colorizer.rb +30 -0
  13. data/lib/nanoc/cli/cleaning_stream.rb +91 -0
  14. data/lib/nanoc/cli/command_runner.rb +3 -11
  15. data/lib/nanoc/cli/commands/compile.rb +2 -2
  16. data/lib/nanoc/cli/commands/{create_item.rb → create-item.rb} +6 -7
  17. data/lib/nanoc/cli/commands/{create_layout.rb → create-layout.rb} +9 -10
  18. data/lib/nanoc/cli/commands/{create_site.rb → create-site.rb} +13 -14
  19. data/lib/nanoc/cli/commands/deploy.rb +4 -12
  20. data/lib/nanoc/cli/commands/nanoc.rb +4 -2
  21. data/lib/nanoc/cli/commands/prune.rb +1 -1
  22. data/lib/nanoc/cli/commands/{debug.rb → show-data.rb} +6 -5
  23. data/lib/nanoc/cli/commands/{info.rb → show-plugins.rb} +6 -6
  24. data/lib/nanoc/cli/commands/show-rules.rb +69 -0
  25. data/lib/nanoc/cli/commands/update.rb +1 -2
  26. data/lib/nanoc/cli/commands/validate-css.rb +24 -0
  27. data/lib/nanoc/cli/commands/validate-html.rb +24 -0
  28. data/lib/nanoc/cli/commands/validate-links.rb +35 -0
  29. data/lib/nanoc/cli/commands/watch.rb +3 -3
  30. data/lib/nanoc/cli/error_handler.rb +142 -26
  31. data/lib/nanoc/cli/logger.rb +4 -21
  32. data/lib/nanoc/cli/stream_cleaners.rb +14 -0
  33. data/lib/nanoc/cli/stream_cleaners/abstract.rb +23 -0
  34. data/lib/nanoc/cli/stream_cleaners/ansi_colors.rb +15 -0
  35. data/lib/nanoc/cli/stream_cleaners/utf8.rb +16 -0
  36. data/lib/nanoc/extra/deployers/rsync.rb +2 -7
  37. data/lib/nanoc/extra/pruner.rb +3 -3
  38. data/lib/nanoc/extra/validators/links.rb +14 -3
  39. data/lib/nanoc/filters.rb +4 -0
  40. data/lib/nanoc/filters/handlebars.rb +30 -0
  41. data/lib/nanoc/filters/mustache.rb +2 -2
  42. data/lib/nanoc/filters/pandoc.rb +20 -0
  43. data/lib/nanoc/helpers/filtering.rb +1 -1
  44. data/lib/nanoc/tasks/validate.rake +10 -68
  45. data/nanoc.gemspec +0 -16
  46. data/test/cli/commands/test_create_site.rb +1 -1
  47. data/test/cli/commands/test_deploy.rb +45 -0
  48. data/test/cli/test_cli.rb +1 -1
  49. data/test/extra/validators/test_links.rb +15 -5
  50. data/test/filters/test_handlebars.rb +42 -0
  51. data/test/filters/test_mustache.rb +19 -0
  52. data/test/filters/test_pandoc.rb +18 -0
  53. metadata +23 -33
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+
3
+ usage 'show-rules [thing]'
4
+ aliases :explain
5
+ summary 'describe the rules for each item'
6
+ description <<-EOS
7
+ Prints the rules used for all items and layouts in the current site. An argument can be given, which can be either an item identifier (e.g. /foo/), the path to the source file (e.g. content/foo.html) or the path to the output file (e.g. output/foo.html).
8
+ EOS
9
+
10
+ module Nanoc::CLI::Commands
11
+
12
+ class ShowRules < ::Nanoc::CLI::CommandRunner
13
+
14
+ def run
15
+ self.require_site
16
+
17
+ @c = Nanoc::CLI::ANSIStringColorizer
18
+ @calc = self.site.compiler.rule_memory_calculator
19
+
20
+ # TODO explain /foo/
21
+ # TODO explain content/foo.html
22
+ # TODO explain output/foo/index.html
23
+
24
+ self.site.items.each { |i| self.explain_item(i) }
25
+ self.site.layouts.each { |l| self.explain_layout(l) }
26
+ end
27
+
28
+ protected
29
+
30
+ def explain_item(item)
31
+ puts "#{@c.c('Item ' + item.identifier, :bold, :yellow)}:"
32
+ puts " (from #{item[:filename]})" if item[:filename]
33
+ item.reps.each do |rep|
34
+ puts " Rep #{rep.name}:"
35
+ if @calc[rep].empty? && rep.raw_path.nil?
36
+ puts " (nothing)"
37
+ else
38
+ @calc[rep].each do |mem|
39
+ puts ' %s %s' % [
40
+ @c.c(format('%-10s', mem[0].to_s), :blue),
41
+ mem[1..-1].map { |m| m.inspect }.join(', ')
42
+ ]
43
+ end
44
+ if rep.raw_path
45
+ puts ' %s %s' % [
46
+ @c.c(format('%-10s', 'write to'), :blue),
47
+ rep.raw_path
48
+ ]
49
+ end
50
+ end
51
+ end
52
+ puts
53
+ end
54
+
55
+ def explain_layout(layout)
56
+ puts "#{@c.c('Layout ' + layout.identifier, :bold, :yellow)}:"
57
+ puts " (from #{layout[:filename]})" if layout[:filename]
58
+ puts " %s %s" % [
59
+ @c.c(format('%-10s', 'filter'), :blue),
60
+ @calc[layout].map { |m| m.inspect }.join(', ')
61
+ ]
62
+ puts
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+
69
+ runner Nanoc::CLI::Commands::ShowRules
@@ -22,8 +22,7 @@ module Nanoc::CLI::Commands
22
22
  def run
23
23
  # Check arguments
24
24
  if arguments.size != 0
25
- $stderr.puts "usage: #{command.usage}"
26
- exit 1
25
+ raise Nanoc::Errors::GenericTrivial, "usage: #{command.usage}"
27
26
  end
28
27
 
29
28
  # Make sure we are in a nanoc site directory
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ usage 'validate-css [options]'
4
+ aliases :validate_css, :vcss
5
+ summary 'validate the site’s CSS'
6
+ description <<-EOS
7
+ Validates the site’s CSS files.
8
+ EOS
9
+
10
+ module Nanoc::CLI::Commands
11
+
12
+ class ValidateCSS < ::Nanoc::CLI::CommandRunner
13
+
14
+ def run
15
+ require_site
16
+ validator = ::Nanoc::Extra::Validators::W3C.new(site.config[:output_dir], [ :css ])
17
+ validator.run
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+ runner Nanoc::CLI::Commands::ValidateCSS
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ usage 'validate-html [options]'
4
+ aliases :validate_html, :vhtml
5
+ summary 'validate the site’s HTML'
6
+ description <<-EOS
7
+ Validates the site’s HTML files.
8
+ EOS
9
+
10
+ module Nanoc::CLI::Commands
11
+
12
+ class ValidateHTML < ::Nanoc::CLI::CommandRunner
13
+
14
+ def run
15
+ require_site
16
+ validator = ::Nanoc::Extra::Validators::W3C.new(site.config[:output_dir], [ :html ])
17
+ validator.run
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+ runner Nanoc::CLI::Commands::ValidateHTML
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ usage 'validate-links [options]'
4
+ aliases :validate_links, :vlink
5
+ summary 'validate links in site'
6
+ description <<-EOS
7
+ Validates the site’s links. By default, both internal and external links will be checked.
8
+ EOS
9
+
10
+ flag :i, :internal, 'validate internal links only'
11
+ flag :e, :external, 'validate external links only'
12
+
13
+ module Nanoc::CLI::Commands
14
+
15
+ class ValidateLinks < ::Nanoc::CLI::CommandRunner
16
+
17
+ def run
18
+ require_site
19
+
20
+ dir = site.config[:output_dir]
21
+ index_filenames = site.config[:index_filenames]
22
+
23
+ validator = ::Nanoc::Extra::Validators::Links.new(
24
+ dir,
25
+ index_filenames,
26
+ :internal => (options[:external] ? false : true),
27
+ :external => (options[:internal] ? false : true))
28
+ validator.run
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ runner Nanoc::CLI::Commands::ValidateLinks
@@ -30,9 +30,9 @@ module Nanoc::CLI::Commands
30
30
 
31
31
  # Notify
32
32
  if filename
33
- print "Change detected to #{filename}; recompiling… ".make_compatible_with_env
33
+ print "Change detected to #{filename}; recompiling… "
34
34
  else
35
- print "Watcher started; compiling the entire site… ".make_compatible_with_env
35
+ print "Watcher started; compiling the entire site… "
36
36
  end
37
37
 
38
38
  # Recompile
@@ -71,7 +71,7 @@ module Nanoc::CLI::Commands
71
71
  files_to_watch.delete_if { |f| !File.file?(f) }
72
72
 
73
73
  # Watch
74
- puts "Watching for changes…".make_compatible_with_env
74
+ puts "Watching for changes…"
75
75
  watcher = lambda do |*args|
76
76
  update(&rebuilder)
77
77
  delete(&rebuilder)
@@ -61,6 +61,9 @@ module Nanoc::CLI
61
61
 
62
62
  # Run
63
63
  yield
64
+ rescue Nanoc::Errors::GenericTrivial => e
65
+ $stderr.puts "Error: #{e.message}"
66
+ exit(1)
64
67
  rescue Interrupt => e
65
68
  exit(1)
66
69
  rescue StandardError, ScriptError => e
@@ -85,50 +88,149 @@ module Nanoc::CLI
85
88
  #
86
89
  # @return [void]
87
90
  def print_error(error)
91
+ write_compact_error(error, $stderr)
92
+ File.open('crash.log', 'w') { |io| write_verbose_error(error, io) }
93
+ end
94
+
95
+ # Writes a compact representation of the error, suitable for a terminal, on
96
+ # the given stream (probably stderr).
97
+ #
98
+ # @param [Error] error The error that should be described
99
+ #
100
+ # @param [IO] stream The stream to write the description too
101
+ #
102
+ # @api private
103
+ #
104
+ # @return [void]
105
+ def write_compact_error(error, stream)
88
106
  # Header
89
- $stderr.puts
90
- $stderr.puts "Captain! We’ve been hit!".make_compatible_with_env
107
+ stream.puts
108
+ stream.puts "Captain! We’ve been hit!"
91
109
 
92
110
  # Exception and resolution (if any)
93
- $stderr.puts
94
- $stderr.puts '=== MESSAGE:'
95
- $stderr.puts
96
- $stderr.puts "#{error.class}: #{error.message}"
111
+ stream.puts
112
+ stream.puts format_title('Message:')
113
+ stream.puts
114
+ stream.puts "#{error.class}: #{error.message}"
97
115
  resolution = self.resolution_for(error)
98
- $stderr.puts "#{resolution}" if resolution
116
+ stream.puts "#{resolution}" if resolution
99
117
 
100
118
  # Compilation stack
101
- $stderr.puts
102
- $stderr.puts '=== COMPILATION STACK:'
103
- $stderr.puts
119
+ stream.puts
120
+ stream.puts format_title('Compilation stack:')
121
+ stream.puts
104
122
  if self.stack.empty?
105
- $stderr.puts " (empty)"
123
+ stream.puts " (empty)"
106
124
  else
107
125
  self.stack.reverse.each do |obj|
108
126
  if obj.is_a?(Nanoc::ItemRep)
109
- $stderr.puts " - [item] #{obj.item.identifier} (rep #{obj.name})"
127
+ stream.puts " - [item] #{obj.item.identifier} (rep #{obj.name})"
110
128
  else # layout
111
- $stderr.puts " - [layout] #{obj.identifier}"
129
+ stream.puts " - [layout] #{obj.identifier}"
112
130
  end
113
131
  end
114
132
  end
115
133
 
116
134
  # Backtrace
117
- $stderr.puts
118
- $stderr.puts '=== BACKTRACE:'
119
- $stderr.puts
120
- $stderr.puts error.backtrace.to_enum(:each_with_index).map { |item, index| " #{index}. #{item}" }.join("\n")
121
-
122
- # Extra information
123
- $stderr.puts
124
- $stderr.puts '=== VERSION INFORMATION:'
125
- $stderr.puts
126
- $stderr.puts Nanoc.version_information
135
+ stream.puts
136
+ stream.puts format_title('Stack trace:')
137
+ stream.puts
138
+ count = 10
139
+ error.backtrace[0...count].each_with_index do |item, index|
140
+ stream.puts " #{index}. #{item}"
141
+ end
142
+ if error.backtrace.size > count
143
+ puts " ... #{error.backtrace.size - count} more lines omitted. See full crash log for details."
144
+ end
127
145
 
128
146
  # Issue link
129
- $stderr.puts
130
- $stderr.puts "If you believe this is a bug in nanoc, please do report it at"
131
- $stderr.puts "<https://github.com/ddfreyne/nanoc/issues/new>--thanks!"
147
+ stream.puts
148
+ stream.puts "If you believe this is a bug in nanoc, please do report it at"
149
+ stream.puts "-> https://github.com/ddfreyne/nanoc/issues/new <-"
150
+ stream.puts
151
+ stream.puts "A detailed crash log has been written to ./crash.log."
152
+ end
153
+
154
+ # Writes a verbose representation of the error on the given stream.
155
+ #
156
+ # @param [Error] error The error that should be described
157
+ #
158
+ # @param [IO] stream The stream to write the description too
159
+ #
160
+ # @api private
161
+ #
162
+ # @return [void]
163
+ def write_verbose_error(error, stream)
164
+ # Date and time
165
+ stream.puts "Crashlog created at #{Time.now}"
166
+ stream.puts
167
+
168
+ # Exception and resolution (if any)
169
+ stream.puts '=== MESSAGE:'
170
+ stream.puts
171
+ stream.puts "#{error.class}: #{error.message}"
172
+ resolution = self.resolution_for(error)
173
+ stream.puts "#{resolution}" if resolution
174
+ stream.puts
175
+
176
+ # Compilation stack
177
+ stream.puts '=== COMPILATION STACK:'
178
+ stream.puts
179
+ if self.stack.empty?
180
+ stream.puts " (empty)"
181
+ else
182
+ self.stack.reverse.each do |obj|
183
+ if obj.is_a?(Nanoc::ItemRep)
184
+ stream.puts " - [item] #{obj.item.identifier} (rep #{obj.name})"
185
+ else # layout
186
+ stream.puts " - [layout] #{obj.identifier}"
187
+ end
188
+ end
189
+ end
190
+ stream.puts
191
+
192
+ # Backtrace
193
+ stream.puts '=== BACKTRACE:'
194
+ stream.puts
195
+ stream.puts error.backtrace.to_enum(:each_with_index).map { |item, index| " #{index}. #{item}" }.join("\n")
196
+ stream.puts
197
+
198
+ # Version information
199
+ stream.puts '=== VERSION INFORMATION:'
200
+ stream.puts
201
+ stream.puts Nanoc.version_information
202
+ stream.puts
203
+
204
+ # Installed gems
205
+ stream.puts '=== INSTALLED GEMS:'
206
+ stream.puts
207
+ self.gems_and_versions.each do |g|
208
+ stream.puts " #{g.first} #{g.last.join(', ')}"
209
+ end
210
+ stream.puts
211
+
212
+ # Environment
213
+ stream.puts '=== ENVIRONMENT:'
214
+ stream.puts
215
+ ENV.sort.each do |e|
216
+ stream.puts "#{e.first} => #{e.last.inspect}"
217
+ end
218
+ stream.puts
219
+
220
+ # Gemfile
221
+ if File.exist?('Gemfile.lock')
222
+ stream.puts '=== GEMFILE.LOCK:'
223
+ stream.puts
224
+ stream.puts File.read('Gemfile.lock')
225
+ stream.puts
226
+ end
227
+
228
+ # Load paths
229
+ stream.puts '=== $LOAD_PATH:'
230
+ stream.puts
231
+ $LOAD_PATH.each_with_index do |i, index|
232
+ stream.puts " #{index}. #{i}"
233
+ end
132
234
  end
133
235
 
134
236
  protected
@@ -155,6 +257,15 @@ module Nanoc::CLI
155
257
  (compiler && compiler.stack) || []
156
258
  end
157
259
 
260
+ def gems_and_versions
261
+ gems = {}
262
+ Gem::Specification.find_all.sort_by { |s| [ s.name, s.version ] }.each do |spec|
263
+ gems[spec.name] ||= []
264
+ gems[spec.name] << spec.version.to_s
265
+ end
266
+ gems
267
+ end
268
+
158
269
  # A hash that contains the name of the gem for a given required file. If a
159
270
  # `#require` fails, the gem name is looked up in this hash.
160
271
  GEM_NAMES = {
@@ -168,6 +279,7 @@ module Nanoc::CLI
168
279
  'fog' => 'fog',
169
280
  'fssm' => 'fssm',
170
281
  'haml' => 'haml',
282
+ 'handlebars' => 'hbs',
171
283
  'json' => 'json',
172
284
  'kramdown' => 'kramdown',
173
285
  'less' => 'less',
@@ -216,6 +328,10 @@ module Nanoc::CLI
216
328
  end
217
329
  end
218
330
 
331
+ def format_title(s)
332
+ "\e[1m\e[31m" + s + "\e[0m"
333
+ end
334
+
219
335
  end
220
336
 
221
337
  end
@@ -27,27 +27,10 @@ module Nanoc::CLI
27
27
  # @return [Symbol] The log level
28
28
  attr_accessor :level
29
29
 
30
- # @return [Boolean] True if color should be used, false otherwise
31
- attr_writer :color
32
-
33
30
  def initialize
34
31
  @level = :high
35
32
  end
36
33
 
37
- # @return [Boolean] true if colors are enabled, false otherwise
38
- def color?
39
- if @color.nil?
40
- @color = true
41
- begin
42
- require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /mswin|mingw/
43
- rescue LoadError
44
- @color = false
45
- end
46
- end
47
-
48
- @color
49
- end
50
-
51
34
  # Logs a file-related action.
52
35
  #
53
36
  # @param [:high, :low] level The importance of this action
@@ -57,15 +40,15 @@ module Nanoc::CLI
57
40
  # @param [String] name The name of the file the action was performed on
58
41
  #
59
42
  # @return [void]
60
- def file(level, action, identifier, duration=nil)
43
+ def file(level, action, name, duration=nil)
61
44
  log(
62
45
  level,
63
46
  '%s%12s%s %s%s' % [
64
- color? ? ACTION_COLORS[action.to_sym] : '',
47
+ ACTION_COLORS[action.to_sym],
65
48
  action,
66
- color? ? "\e[0m" : '',
49
+ "\e[0m",
67
50
  duration.nil? ? '' : "[%2.2fs] " % [ duration ],
68
- identifier
51
+ name
69
52
  ]
70
53
  )
71
54
  end