nanoc 3.3.7 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +133 -0
- data/NEWS.md +15 -0
- data/lib/nanoc.rb +2 -2
- data/lib/nanoc/base/compilation/compiler.rb +1 -1
- data/lib/nanoc/base/compilation/item_rep_proxy.rb +3 -3
- data/lib/nanoc/base/core_ext/string.rb +0 -18
- data/lib/nanoc/base/errors.rb +24 -19
- data/lib/nanoc/base/plugin_registry.rb +1 -1
- data/lib/nanoc/base/result_data/item_rep.rb +1 -2
- data/lib/nanoc/base/source_data/site.rb +1 -1
- data/lib/nanoc/cli.rb +46 -4
- data/lib/nanoc/cli/ansi_string_colorizer.rb +30 -0
- data/lib/nanoc/cli/cleaning_stream.rb +91 -0
- data/lib/nanoc/cli/command_runner.rb +3 -11
- data/lib/nanoc/cli/commands/compile.rb +2 -2
- data/lib/nanoc/cli/commands/{create_item.rb → create-item.rb} +6 -7
- data/lib/nanoc/cli/commands/{create_layout.rb → create-layout.rb} +9 -10
- data/lib/nanoc/cli/commands/{create_site.rb → create-site.rb} +13 -14
- data/lib/nanoc/cli/commands/deploy.rb +4 -12
- data/lib/nanoc/cli/commands/nanoc.rb +4 -2
- data/lib/nanoc/cli/commands/prune.rb +1 -1
- data/lib/nanoc/cli/commands/{debug.rb → show-data.rb} +6 -5
- data/lib/nanoc/cli/commands/{info.rb → show-plugins.rb} +6 -6
- data/lib/nanoc/cli/commands/show-rules.rb +69 -0
- data/lib/nanoc/cli/commands/update.rb +1 -2
- data/lib/nanoc/cli/commands/validate-css.rb +24 -0
- data/lib/nanoc/cli/commands/validate-html.rb +24 -0
- data/lib/nanoc/cli/commands/validate-links.rb +35 -0
- data/lib/nanoc/cli/commands/watch.rb +3 -3
- data/lib/nanoc/cli/error_handler.rb +142 -26
- data/lib/nanoc/cli/logger.rb +4 -21
- data/lib/nanoc/cli/stream_cleaners.rb +14 -0
- data/lib/nanoc/cli/stream_cleaners/abstract.rb +23 -0
- data/lib/nanoc/cli/stream_cleaners/ansi_colors.rb +15 -0
- data/lib/nanoc/cli/stream_cleaners/utf8.rb +16 -0
- data/lib/nanoc/extra/deployers/rsync.rb +2 -7
- data/lib/nanoc/extra/pruner.rb +3 -3
- data/lib/nanoc/extra/validators/links.rb +14 -3
- data/lib/nanoc/filters.rb +4 -0
- data/lib/nanoc/filters/handlebars.rb +30 -0
- data/lib/nanoc/filters/mustache.rb +2 -2
- data/lib/nanoc/filters/pandoc.rb +20 -0
- data/lib/nanoc/helpers/filtering.rb +1 -1
- data/lib/nanoc/tasks/validate.rake +10 -68
- data/nanoc.gemspec +0 -16
- data/test/cli/commands/test_create_site.rb +1 -1
- data/test/cli/commands/test_deploy.rb +45 -0
- data/test/cli/test_cli.rb +1 -1
- data/test/extra/validators/test_links.rb +15 -5
- data/test/filters/test_handlebars.rb +42 -0
- data/test/filters/test_mustache.rb +19 -0
- data/test/filters/test_pandoc.rb +18 -0
- 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
|
-
|
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… "
|
33
|
+
print "Change detected to #{filename}; recompiling… "
|
34
34
|
else
|
35
|
-
print "Watcher started; compiling the entire site… "
|
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…"
|
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
|
-
|
90
|
-
|
107
|
+
stream.puts
|
108
|
+
stream.puts "Captain! We’ve been hit!"
|
91
109
|
|
92
110
|
# Exception and resolution (if any)
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
116
|
+
stream.puts "#{resolution}" if resolution
|
99
117
|
|
100
118
|
# Compilation stack
|
101
|
-
|
102
|
-
|
103
|
-
|
119
|
+
stream.puts
|
120
|
+
stream.puts format_title('Compilation stack:')
|
121
|
+
stream.puts
|
104
122
|
if self.stack.empty?
|
105
|
-
|
123
|
+
stream.puts " (empty)"
|
106
124
|
else
|
107
125
|
self.stack.reverse.each do |obj|
|
108
126
|
if obj.is_a?(Nanoc::ItemRep)
|
109
|
-
|
127
|
+
stream.puts " - [item] #{obj.item.identifier} (rep #{obj.name})"
|
110
128
|
else # layout
|
111
|
-
|
129
|
+
stream.puts " - [layout] #{obj.identifier}"
|
112
130
|
end
|
113
131
|
end
|
114
132
|
end
|
115
133
|
|
116
134
|
# Backtrace
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
130
|
-
|
131
|
-
|
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
|
data/lib/nanoc/cli/logger.rb
CHANGED
@@ -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,
|
43
|
+
def file(level, action, name, duration=nil)
|
61
44
|
log(
|
62
45
|
level,
|
63
46
|
'%s%12s%s %s%s' % [
|
64
|
-
|
47
|
+
ACTION_COLORS[action.to_sym],
|
65
48
|
action,
|
66
|
-
|
49
|
+
"\e[0m",
|
67
50
|
duration.nil? ? '' : "[%2.2fs] " % [ duration ],
|
68
|
-
|
51
|
+
name
|
69
52
|
]
|
70
53
|
)
|
71
54
|
end
|