nanoc 3.4.3 → 3.5.0b1
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.
- data/CONTRIBUTING.md +25 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +22 -13
- data/NEWS.md +27 -0
- data/README.md +3 -1
- data/lib/nanoc.rb +2 -2
- data/lib/nanoc/base/compilation/compiler_dsl.rb +19 -0
- data/lib/nanoc/base/core_ext/array.rb +18 -8
- data/lib/nanoc/base/core_ext/hash.rb +18 -8
- data/lib/nanoc/base/core_ext/pathname.rb +2 -8
- data/lib/nanoc/base/plugin_registry.rb +57 -19
- data/lib/nanoc/base/result_data/item_rep.rb +3 -15
- data/lib/nanoc/base/source_data/item.rb +1 -1
- data/lib/nanoc/base/source_data/layout.rb +1 -1
- data/lib/nanoc/base/source_data/site.rb +15 -19
- data/lib/nanoc/cli.rb +28 -23
- data/lib/nanoc/cli/command_runner.rb +4 -0
- data/lib/nanoc/cli/commands/autocompile.rb +15 -6
- data/lib/nanoc/cli/commands/check.rb +47 -0
- data/lib/nanoc/cli/commands/compile.rb +271 -195
- data/lib/nanoc/cli/commands/create-site.rb +5 -5
- data/lib/nanoc/cli/commands/deploy.rb +16 -4
- data/lib/nanoc/cli/commands/prune.rb +3 -3
- data/lib/nanoc/cli/commands/show-data.rb +73 -58
- data/lib/nanoc/cli/commands/show-rules.rb +1 -1
- data/lib/nanoc/cli/commands/validate-css.rb +2 -3
- data/lib/nanoc/cli/commands/validate-html.rb +2 -3
- data/lib/nanoc/cli/commands/validate-links.rb +5 -11
- data/lib/nanoc/cli/commands/view.rb +1 -1
- data/lib/nanoc/cli/commands/watch.rb +38 -20
- data/lib/nanoc/cli/error_handler.rb +122 -122
- data/lib/nanoc/data_sources.rb +2 -0
- data/lib/nanoc/data_sources/filesystem_unified.rb +1 -1
- data/lib/nanoc/data_sources/filesystem_verbose.rb +1 -1
- data/lib/nanoc/data_sources/static.rb +60 -0
- data/lib/nanoc/extra.rb +2 -0
- data/lib/nanoc/extra/checking.rb +16 -0
- data/lib/nanoc/extra/checking/check.rb +33 -0
- data/lib/nanoc/extra/checking/checks.rb +19 -0
- data/lib/nanoc/extra/checking/checks/css.rb +23 -0
- data/lib/nanoc/extra/checking/checks/external_links.rb +149 -0
- data/lib/nanoc/extra/checking/checks/html.rb +24 -0
- data/lib/nanoc/extra/checking/checks/internal_links.rb +57 -0
- data/lib/nanoc/extra/checking/checks/stale.rb +23 -0
- data/lib/nanoc/extra/checking/dsl.rb +31 -0
- data/lib/nanoc/extra/checking/issue.rb +19 -0
- data/lib/nanoc/extra/checking/runner.rb +130 -0
- data/lib/nanoc/extra/link_collector.rb +57 -0
- data/lib/nanoc/extra/pruner.rb +1 -1
- data/lib/nanoc/extra/validators/links.rb +5 -262
- data/lib/nanoc/extra/validators/w3c.rb +8 -76
- data/lib/nanoc/filters/colorize_syntax.rb +1 -1
- data/lib/nanoc/filters/handlebars.rb +2 -2
- data/lib/nanoc/filters/less.rb +1 -1
- data/lib/nanoc/filters/redcarpet.rb +1 -1
- data/lib/nanoc/filters/rubypants.rb +1 -1
- data/lib/nanoc/filters/slim.rb +1 -1
- data/lib/nanoc/helpers/blogging.rb +163 -104
- data/lib/nanoc/helpers/xml_sitemap.rb +9 -3
- data/tasks/doc.rake +2 -1
- data/test/base/core_ext/array_spec.rb +4 -4
- data/test/base/core_ext/hash_spec.rb +7 -7
- data/test/base/core_ext/pathname_spec.rb +12 -2
- data/test/base/test_compiler_dsl.rb +24 -0
- data/test/base/test_item_rep.rb +58 -26
- data/test/cli/commands/test_watch.rb +0 -8
- data/test/data_sources/test_static.rb +66 -0
- data/test/extra/checking/checks/test_css.rb +40 -0
- data/test/extra/checking/checks/test_external_links.rb +76 -0
- data/test/extra/checking/checks/test_html.rb +40 -0
- data/test/extra/checking/checks/test_internal_links.rb +46 -0
- data/test/extra/checking/checks/test_stale.rb +49 -0
- data/test/extra/checking/test_check.rb +16 -0
- data/test/extra/checking/test_dsl.rb +20 -0
- data/test/extra/checking/test_runner.rb +15 -0
- data/test/extra/test_link_collector.rb +93 -0
- data/test/extra/validators/test_links.rb +0 -64
- data/test/extra/validators/test_w3c.rb +20 -26
- data/test/filters/test_colorize_syntax.rb +15 -0
- data/test/filters/test_less.rb +14 -0
- data/test/filters/test_pandoc.rb +5 -1
- data/test/helpers/test_blogging.rb +52 -8
- data/test/helpers/test_xml_sitemap.rb +68 -0
- data/test/test_gem.rb +1 -1
- metadata +31 -6
@@ -4,7 +4,7 @@ usage 'create-site [options] path'
|
|
4
4
|
aliases :create_site, :cs
|
5
5
|
summary 'create a site'
|
6
6
|
description <<-EOS
|
7
|
-
Create a new site at the given path. The site will use the filesystem_unified data source by default, but this can be changed using the
|
7
|
+
Create a new site at the given path. The site will use the `filesystem_unified` data source by default, but this can be changed using the `--datasource` commandline option.
|
8
8
|
EOS
|
9
9
|
|
10
10
|
required :d, :datasource, 'specify the data source for the new site'
|
@@ -208,9 +208,9 @@ a:hover {
|
|
208
208
|
|
209
209
|
#main p {
|
210
210
|
margin: 20px 0;
|
211
|
-
|
211
|
+
|
212
212
|
font-size: 15px;
|
213
|
-
|
213
|
+
|
214
214
|
line-height: 20px;
|
215
215
|
}
|
216
216
|
|
@@ -220,7 +220,7 @@ a:hover {
|
|
220
220
|
|
221
221
|
#main li {
|
222
222
|
font-size: 15px;
|
223
|
-
|
223
|
+
|
224
224
|
line-height: 20px;
|
225
225
|
}
|
226
226
|
|
@@ -273,7 +273,7 @@ EOS
|
|
273
273
|
<head>
|
274
274
|
<meta charset="utf-8">
|
275
275
|
<title>A Brand New nanoc Site - <%= @item[:title] %></title>
|
276
|
-
<link rel="stylesheet"
|
276
|
+
<link rel="stylesheet" href="/style.css">
|
277
277
|
|
278
278
|
<!-- you don't need to keep this, but it's cool for stats! -->
|
279
279
|
<meta name="generator" content="nanoc <%= Nanoc::VERSION %>">
|
@@ -9,15 +9,16 @@ deployer_names = deployers.keys.sort_by { |k| k.to_s }
|
|
9
9
|
usage 'deploy [options]'
|
10
10
|
summary 'deploy the compiled site'
|
11
11
|
description <<-EOS
|
12
|
-
Deploys the compiled site. The compiled site contents in the output directory will be uploaded to the destination, which is specified using the
|
12
|
+
Deploys the compiled site. The compiled site contents in the output directory will be uploaded to the destination, which is specified using the `--target` option.
|
13
13
|
|
14
14
|
Available deployers: #{deployer_names.join(', ')}
|
15
15
|
|
16
16
|
EOS
|
17
17
|
|
18
|
-
option :t, :target,
|
19
|
-
flag :
|
20
|
-
|
18
|
+
option :t, :target, 'specify the location to deploy to (default: `default`)', :argument => :required
|
19
|
+
flag :C, :'no-check', 'do not run the issue checks marked for deployment'
|
20
|
+
flag :L, :list, 'list available locations to deploy to'
|
21
|
+
option :n, :'dry-run', 'show what would be deployed'
|
21
22
|
|
22
23
|
module Nanoc::CLI::Commands
|
23
24
|
|
@@ -57,6 +58,17 @@ module Nanoc::CLI::Commands
|
|
57
58
|
raise Nanoc::Errors::GenericTrivial, "The specified deploy target has an unrecognised kind “#{name}” (expected one of #{names.join(', ')})."
|
58
59
|
end
|
59
60
|
|
61
|
+
# Check
|
62
|
+
unless options[:'no-check']
|
63
|
+
puts "Running issue checks…"
|
64
|
+
ok = Nanoc::Extra::Checking::Runner.new(site).run_for_deploy
|
65
|
+
if !ok
|
66
|
+
puts "Issues found, deploy aborted."
|
67
|
+
return
|
68
|
+
end
|
69
|
+
puts "No issues found. Deploying!"
|
70
|
+
end
|
71
|
+
|
60
72
|
# Run
|
61
73
|
deployer = deployer_class.new(
|
62
74
|
site.config[:output_dir],
|
@@ -5,10 +5,10 @@ summary 'remove files not managed by nanoc from the output directory'
|
|
5
5
|
description <<-EOS
|
6
6
|
Find all files in the output directory that do not correspond to an item
|
7
7
|
managed by nanoc and remove them. Since this is a hazardous operation, an
|
8
|
-
additional
|
8
|
+
additional `--yes` flag is needed as confirmation.
|
9
9
|
|
10
|
-
Also see the auto_prune site configuration option in config.
|
11
|
-
automatically prune after compilation.
|
10
|
+
Also see the `auto_prune` site configuration option in `config.yamlz, which
|
11
|
+
will automatically prune after compilation.
|
12
12
|
EOS
|
13
13
|
|
14
14
|
flag :y, :yes, 'confirm deletion'
|
@@ -13,26 +13,59 @@ module Nanoc::CLI::Commands
|
|
13
13
|
class ShowData < ::Nanoc::CLI::CommandRunner
|
14
14
|
|
15
15
|
def run
|
16
|
-
# Make sure we are in a nanoc site directory
|
17
|
-
print "Loading site data... "
|
18
16
|
self.require_site
|
19
|
-
puts "done"
|
20
|
-
puts
|
21
17
|
|
22
18
|
# Get data
|
23
|
-
items
|
24
|
-
|
25
|
-
layouts
|
19
|
+
items = self.site.items
|
20
|
+
item_reps = items.map { |i| i.reps }.flatten
|
21
|
+
layouts = self.site.layouts
|
26
22
|
|
27
23
|
# Get dependency tracker
|
28
24
|
compiler = self.site.compiler
|
29
25
|
compiler.load
|
30
26
|
dependency_tracker = compiler.dependency_tracker
|
31
27
|
|
32
|
-
# Print
|
33
|
-
|
34
|
-
|
28
|
+
# Print data
|
29
|
+
self.print_item_dependencies(items, dependency_tracker)
|
30
|
+
self.print_item_rep_paths(items)
|
31
|
+
self.print_item_rep_outdatedness(items, compiler)
|
32
|
+
self.print_layouts(layouts, compiler)
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def sorted_with_prev(objects)
|
38
|
+
prev = nil
|
39
|
+
objects.sort_by { |o| o.identifier }.each do |object|
|
40
|
+
yield(object, prev)
|
41
|
+
prev = object
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def sorted_reps_with_prev(items)
|
46
|
+
prev = nil
|
35
47
|
items.sort_by { |i| i.identifier }.each do |item|
|
48
|
+
item.reps.sort_by { |r| r.name.to_s }.each do |rep|
|
49
|
+
yield(rep, prev)
|
50
|
+
prev = rep
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def print_header(title)
|
56
|
+
header = '=' * 78
|
57
|
+
header[3..(title.length+5)] = " #{title} "
|
58
|
+
|
59
|
+
puts
|
60
|
+
puts header
|
61
|
+
puts
|
62
|
+
end
|
63
|
+
|
64
|
+
def print_item_dependencies(items, dependency_tracker)
|
65
|
+
self.print_header('Item dependencies')
|
66
|
+
|
67
|
+
self.sorted_with_prev(items) do |item, prev|
|
68
|
+
puts if prev
|
36
69
|
puts "item #{item.identifier} depends on:"
|
37
70
|
predecessors = dependency_tracker.objects_causing_outdatedness_of(item).sort_by { |i| i ? i.identifier : '' }
|
38
71
|
predecessors.each do |pred|
|
@@ -43,63 +76,45 @@ module Nanoc::CLI::Commands
|
|
43
76
|
end
|
44
77
|
end
|
45
78
|
puts " (nothing)" if predecessors.empty?
|
46
|
-
puts
|
47
79
|
end
|
80
|
+
end
|
48
81
|
|
49
|
-
|
50
|
-
|
51
|
-
puts
|
52
|
-
items.sort_by { |i| i.identifier }.each do |item|
|
53
|
-
item.reps.sort_by { |r| r.name.to_s }.each do |rep|
|
54
|
-
puts "item #{item.identifier}, rep #{rep.name}:"
|
55
|
-
if rep.raw_paths.empty?
|
56
|
-
puts " (not written)"
|
57
|
-
end
|
58
|
-
length = rep.raw_paths.keys.map { |s| s.to_s.length }.max
|
59
|
-
rep.raw_paths.each do |snapshot_name, raw_path|
|
60
|
-
puts " [ %-#{length}s ] %s" % [ snapshot_name, raw_path ]
|
61
|
-
end
|
62
|
-
end
|
63
|
-
puts
|
64
|
-
end
|
82
|
+
def print_item_rep_paths(items)
|
83
|
+
self.print_header('Item representation paths')
|
65
84
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
else
|
76
|
-
puts " is not outdated"
|
77
|
-
end
|
85
|
+
self.sorted_reps_with_prev(items) do |rep, prev|
|
86
|
+
puts if prev
|
87
|
+
puts "item #{rep.item.identifier}, rep #{rep.name}:"
|
88
|
+
if rep.raw_paths.empty?
|
89
|
+
puts " (not written)"
|
90
|
+
end
|
91
|
+
length = rep.raw_paths.keys.map { |s| s.to_s.length }.max
|
92
|
+
rep.raw_paths.each do |snapshot_name, raw_path|
|
93
|
+
puts " [ %-#{length}s ] %s" % [ snapshot_name, raw_path ]
|
78
94
|
end
|
79
|
-
puts
|
80
95
|
end
|
96
|
+
end
|
81
97
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
puts
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
98
|
+
def print_item_rep_outdatedness(items, compiler)
|
99
|
+
self.print_header('Item representation outdatedness')
|
100
|
+
|
101
|
+
self.sorted_reps_with_prev(items) do |rep, prev|
|
102
|
+
puts if prev
|
103
|
+
puts "item #{rep.item.identifier}, rep #{rep.name}:"
|
104
|
+
outdatedness_reason = compiler.outdatedness_checker.outdatedness_reason_for(rep)
|
105
|
+
if outdatedness_reason
|
106
|
+
puts " is outdated: #{outdatedness_reason.message}"
|
107
|
+
else
|
108
|
+
puts " is not outdated"
|
94
109
|
end
|
95
|
-
puts " (nothing)" if predecessors.empty?
|
96
|
-
puts
|
97
110
|
end
|
111
|
+
end
|
98
112
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
layouts
|
113
|
+
def print_layouts(layouts, compiler)
|
114
|
+
self.print_header('Layouts')
|
115
|
+
|
116
|
+
self.sorted_with_prev(layouts) do |layout, prev|
|
117
|
+
puts if prev
|
103
118
|
puts "layout #{layout.identifier}:"
|
104
119
|
outdatedness_reason = compiler.outdatedness_checker.outdatedness_reason_for(layout)
|
105
120
|
if outdatedness_reason
|
@@ -4,7 +4,7 @@ usage 'show-rules [thing]'
|
|
4
4
|
aliases :explain
|
5
5
|
summary 'describe the rules for each item'
|
6
6
|
description <<-EOS
|
7
|
-
Prints the rules used for all items and layouts in the current site.
|
7
|
+
Prints the rules used for all items and layouts in the current site.
|
8
8
|
EOS
|
9
9
|
|
10
10
|
module Nanoc::CLI::Commands
|
@@ -3,6 +3,7 @@
|
|
3
3
|
usage 'validate-css [options]'
|
4
4
|
aliases :validate_css, :vcss
|
5
5
|
summary 'validate the site’s CSS'
|
6
|
+
be_hidden
|
6
7
|
description <<-EOS
|
7
8
|
Validates the site’s CSS files.
|
8
9
|
EOS
|
@@ -12,9 +13,7 @@ module Nanoc::CLI::Commands
|
|
12
13
|
class ValidateCSS < ::Nanoc::CLI::CommandRunner
|
13
14
|
|
14
15
|
def run
|
15
|
-
|
16
|
-
validator = ::Nanoc::Extra::Validators::W3C.new(site.config[:output_dir], [ :css ])
|
17
|
-
validator.run
|
16
|
+
Nanoc::CLI.run %w( check css )
|
18
17
|
end
|
19
18
|
|
20
19
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
usage 'validate-html [options]'
|
4
4
|
aliases :validate_html, :vhtml
|
5
5
|
summary 'validate the site’s HTML'
|
6
|
+
be_hidden
|
6
7
|
description <<-EOS
|
7
8
|
Validates the site’s HTML files.
|
8
9
|
EOS
|
@@ -12,9 +13,7 @@ module Nanoc::CLI::Commands
|
|
12
13
|
class ValidateHTML < ::Nanoc::CLI::CommandRunner
|
13
14
|
|
14
15
|
def run
|
15
|
-
|
16
|
-
validator = ::Nanoc::Extra::Validators::W3C.new(site.config[:output_dir], [ :html ])
|
17
|
-
validator.run
|
16
|
+
Nanoc::CLI.run %w( check html )
|
18
17
|
end
|
19
18
|
|
20
19
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
usage 'validate-links [options]'
|
4
4
|
aliases :validate_links, :vlink
|
5
5
|
summary 'validate links in site'
|
6
|
+
be_hidden
|
6
7
|
description <<-EOS
|
7
8
|
Validates the site’s links. By default, both internal and external links will be checked.
|
8
9
|
EOS
|
@@ -15,17 +16,10 @@ module Nanoc::CLI::Commands
|
|
15
16
|
class ValidateLinks < ::Nanoc::CLI::CommandRunner
|
16
17
|
|
17
18
|
def run
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
19
|
+
checks = []
|
20
|
+
checks << 'ilinks' if options[:internal]
|
21
|
+
checks << 'elinks' if options[:external]
|
22
|
+
Nanoc::CLI.run [ 'check', checks ].flatten
|
29
23
|
end
|
30
24
|
|
31
25
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
usage 'view [options]'
|
4
4
|
summary 'start the web server that serves static files'
|
5
5
|
description <<-EOS
|
6
|
-
Start the static web server. Unless specified, the web server will run on port 3000 and listen on all IP addresses. Running this static web server requires
|
6
|
+
Start the static web server. Unless specified, the web server will run on port 3000 and listen on all IP addresses. Running this static web server requires `adsf` (not `asdf`!).
|
7
7
|
EOS
|
8
8
|
|
9
9
|
required :H, :handler, 'specify the handler to use (webrick/mongrel/...)'
|
@@ -11,7 +11,7 @@ module Nanoc::CLI::Commands
|
|
11
11
|
class Watch < ::Nanoc::CLI::CommandRunner
|
12
12
|
|
13
13
|
def run
|
14
|
-
require '
|
14
|
+
require 'listen'
|
15
15
|
require 'pathname'
|
16
16
|
|
17
17
|
require_site
|
@@ -20,12 +20,12 @@ module Nanoc::CLI::Commands
|
|
20
20
|
@notifier = Notifier.new
|
21
21
|
|
22
22
|
# Define rebuilder
|
23
|
-
rebuilder = lambda do |
|
23
|
+
rebuilder = lambda do |file_path|
|
24
24
|
# Determine filename
|
25
|
-
if
|
25
|
+
if file_path.nil?
|
26
26
|
filename = nil
|
27
27
|
else
|
28
|
-
filename = ::Pathname.new(
|
28
|
+
filename = ::Pathname.new(file_path).relative_path_from(::Pathname.new(Dir.getwd)).to_s
|
29
29
|
end
|
30
30
|
|
31
31
|
# Notify
|
@@ -63,24 +63,33 @@ module Nanoc::CLI::Commands
|
|
63
63
|
end
|
64
64
|
|
65
65
|
# Rebuild once
|
66
|
-
rebuilder.call(nil
|
66
|
+
rebuilder.call(nil)
|
67
67
|
|
68
68
|
# Get directories to watch
|
69
|
-
dirs_to_watch = watcher_config[:dirs_to_watch] ||
|
70
|
-
files_to_watch = watcher_config[:files_to_watch] ||
|
71
|
-
files_to_watch.
|
69
|
+
dirs_to_watch = watcher_config[:dirs_to_watch] || ['content', 'layouts', 'lib']
|
70
|
+
files_to_watch = watcher_config[:files_to_watch] || ['config.yaml', 'Rules', 'rules', 'Rules.rb', 'rules.rb']
|
71
|
+
files_to_watch = Regexp.new(files_to_watch.map { |name| "#{Regexp.quote(name)}$"}.join("|"))
|
72
|
+
ignore_dir = Regexp.new(Dir.glob("*").map{|dir| dir if File::ftype(dir) == "directory" }.compact.join("|"))
|
72
73
|
|
73
74
|
# Watch
|
74
75
|
puts "Watching for changes…"
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
76
|
+
|
77
|
+
callback = Proc.new do |modified, added, removed|
|
78
|
+
rebuilder.call(modified[0]) if modified[0]
|
79
|
+
rebuilder.call(added[0]) if added[0]
|
80
|
+
rebuilder.call(removed[0]) if removed[0]
|
81
|
+
end
|
82
|
+
|
83
|
+
listener = Listen::MultiListener.new(*dirs_to_watch).change(&callback)
|
84
|
+
listener_root = Listen::MultiListener.new('', :filter => files_to_watch, :ignore => ignore_dir).change(&callback)
|
85
|
+
|
86
|
+
begin
|
87
|
+
listener_root.start(false)
|
88
|
+
listener.start
|
89
|
+
rescue Interrupt
|
90
|
+
listener.stop
|
91
|
+
listener_root.stop
|
92
|
+
end
|
84
93
|
end
|
85
94
|
|
86
95
|
# Allows sending user notifications in a cross-platform way.
|
@@ -105,12 +114,21 @@ module Nanoc::CLI::Commands
|
|
105
114
|
|
106
115
|
def tool
|
107
116
|
@tool ||= begin
|
108
|
-
|
109
|
-
|
110
|
-
|
117
|
+
require 'terminal-notifier'
|
118
|
+
'terminal-notify'
|
119
|
+
rescue LoadError
|
120
|
+
begin
|
121
|
+
TOOLS.find { |t| !`#{FIND_BINARY_COMMAND} #{t}`.empty? }
|
122
|
+
rescue Errno::ENOENT
|
123
|
+
nil
|
124
|
+
end
|
111
125
|
end
|
112
126
|
end
|
113
127
|
|
128
|
+
def terminal_notify(message)
|
129
|
+
TerminalNotifier.notify(message, :title => "nanoc")
|
130
|
+
end
|
131
|
+
|
114
132
|
def growlnotify(message)
|
115
133
|
system('growlnotify', '-m', message)
|
116
134
|
end
|
@@ -58,6 +58,10 @@ module Nanoc::CLI
|
|
58
58
|
exit!(0)
|
59
59
|
end
|
60
60
|
end
|
61
|
+
Signal.trap('USR1') do
|
62
|
+
puts "Caught USR1; dumping a stack trace"
|
63
|
+
puts caller.map { |i| " #{i}" }.join("\n")
|
64
|
+
end
|
61
65
|
|
62
66
|
# Run
|
63
67
|
yield
|
@@ -89,7 +93,12 @@ module Nanoc::CLI
|
|
89
93
|
# @return [void]
|
90
94
|
def print_error(error)
|
91
95
|
write_compact_error(error, $stderr)
|
92
|
-
|
96
|
+
|
97
|
+
File.open('crash.log', 'w') do |io|
|
98
|
+
cio = Nanoc::CLI.wrap_in_cleaning_stream(io)
|
99
|
+
cio.add_stream_cleaner(::Nanoc::CLI::StreamCleaners::ANSIColors)
|
100
|
+
write_verbose_error(error, cio)
|
101
|
+
end
|
93
102
|
end
|
94
103
|
|
95
104
|
# Writes a compact representation of the error, suitable for a terminal, on
|
@@ -107,48 +116,13 @@ module Nanoc::CLI
|
|
107
116
|
stream.puts
|
108
117
|
stream.puts "Captain! We’ve been hit!"
|
109
118
|
|
110
|
-
#
|
111
|
-
stream
|
112
|
-
stream
|
113
|
-
stream
|
114
|
-
stream.puts "#{error.class}: #{error.message}"
|
115
|
-
resolution = self.resolution_for(error)
|
116
|
-
stream.puts "#{resolution}" if resolution
|
117
|
-
|
118
|
-
# Compilation stack
|
119
|
-
stream.puts
|
120
|
-
stream.puts format_title('Compilation stack:')
|
121
|
-
stream.puts
|
122
|
-
if self.stack.empty?
|
123
|
-
stream.puts " (empty)"
|
124
|
-
else
|
125
|
-
self.stack.reverse.each do |obj|
|
126
|
-
if obj.is_a?(Nanoc::ItemRep)
|
127
|
-
stream.puts " - [item] #{obj.item.identifier} (rep #{obj.name})"
|
128
|
-
else # layout
|
129
|
-
stream.puts " - [layout] #{obj.identifier}"
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# Backtrace
|
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
|
119
|
+
# Sections
|
120
|
+
self.write_error_message( stream, error)
|
121
|
+
self.write_compilation_stack(stream, error)
|
122
|
+
self.write_stack_trace( stream, error)
|
145
123
|
|
146
124
|
# Issue link
|
147
|
-
stream
|
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."
|
125
|
+
self.write_issue_link(stream)
|
152
126
|
end
|
153
127
|
|
154
128
|
# Writes a verbose representation of the error on the given stream.
|
@@ -161,86 +135,19 @@ module Nanoc::CLI
|
|
161
135
|
#
|
162
136
|
# @return [void]
|
163
137
|
def write_verbose_error(error, stream)
|
164
|
-
#
|
138
|
+
# Header
|
165
139
|
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
140
|
|
198
|
-
#
|
199
|
-
stream
|
200
|
-
stream
|
201
|
-
stream
|
202
|
-
stream
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
stream.puts
|
209
|
-
stream.puts uname
|
210
|
-
stream.puts
|
211
|
-
rescue Errno::ENOENT
|
212
|
-
end
|
213
|
-
|
214
|
-
# Installed gems
|
215
|
-
stream.puts '=== INSTALLED GEMS:'
|
216
|
-
stream.puts
|
217
|
-
self.gems_and_versions.each do |g|
|
218
|
-
stream.puts " #{g.first} #{g.last.join(', ')}"
|
219
|
-
end
|
220
|
-
stream.puts
|
221
|
-
|
222
|
-
# Environment
|
223
|
-
stream.puts '=== ENVIRONMENT:'
|
224
|
-
stream.puts
|
225
|
-
ENV.sort.each do |e|
|
226
|
-
stream.puts "#{e.first} => #{e.last.inspect}"
|
227
|
-
end
|
228
|
-
stream.puts
|
229
|
-
|
230
|
-
# Gemfile
|
231
|
-
if File.exist?('Gemfile.lock')
|
232
|
-
stream.puts '=== GEMFILE.LOCK:'
|
233
|
-
stream.puts
|
234
|
-
stream.puts File.read('Gemfile.lock')
|
235
|
-
stream.puts
|
236
|
-
end
|
237
|
-
|
238
|
-
# Load paths
|
239
|
-
stream.puts '=== $LOAD_PATH:'
|
240
|
-
stream.puts
|
241
|
-
$LOAD_PATH.each_with_index do |i, index|
|
242
|
-
stream.puts " #{index}. #{i}"
|
243
|
-
end
|
141
|
+
# Sections
|
142
|
+
self.write_error_message( stream, error, :verbose => true)
|
143
|
+
self.write_compilation_stack( stream, error, :verbose => true)
|
144
|
+
self.write_stack_trace( stream, error, :verbose => true)
|
145
|
+
self.write_version_information(stream, :verbose => true)
|
146
|
+
self.write_system_information( stream, :verbose => true)
|
147
|
+
self.write_installed_gems( stream, :verbose => true)
|
148
|
+
self.write_environment( stream, :verbose => true)
|
149
|
+
self.write_gemfile_lock( stream, :verbose => true)
|
150
|
+
self.write_load_paths( stream, :verbose => true)
|
244
151
|
end
|
245
152
|
|
246
153
|
protected
|
@@ -267,6 +174,7 @@ module Nanoc::CLI
|
|
267
174
|
(compiler && compiler.stack) || []
|
268
175
|
end
|
269
176
|
|
177
|
+
# @return [Hash<String, Array>] A hash containing the gem names as keys and gem versions as value
|
270
178
|
def gems_and_versions
|
271
179
|
gems = {}
|
272
180
|
Gem::Specification.find_all.sort_by { |s| [ s.name, s.version ] }.each do |spec|
|
@@ -287,12 +195,12 @@ module Nanoc::CLI
|
|
287
195
|
'erubis' => 'erubis',
|
288
196
|
'escape' => 'escape',
|
289
197
|
'fog' => 'fog',
|
290
|
-
'fssm' => 'fssm',
|
291
198
|
'haml' => 'haml',
|
292
199
|
'handlebars' => 'hbs',
|
293
200
|
'json' => 'json',
|
294
201
|
'kramdown' => 'kramdown',
|
295
202
|
'less' => 'less',
|
203
|
+
'listen' => 'listen',
|
296
204
|
'markaby' => 'markaby',
|
297
205
|
'maruku' => 'maruku',
|
298
206
|
'mime/types' => 'mime-types',
|
@@ -338,8 +246,100 @@ module Nanoc::CLI
|
|
338
246
|
end
|
339
247
|
end
|
340
248
|
|
341
|
-
def
|
342
|
-
|
249
|
+
def write_section_header(stream, title, params={})
|
250
|
+
stream.puts
|
251
|
+
if params[:verbose]
|
252
|
+
stream.puts '===== ' + title.upcase + ':'
|
253
|
+
else
|
254
|
+
stream.puts "\e[1m\e[31m" + title + ':' + "\e[0m"
|
255
|
+
end
|
256
|
+
stream.puts
|
257
|
+
end
|
258
|
+
|
259
|
+
def write_error_message(stream, error, params={})
|
260
|
+
self.write_section_header(stream, 'Message', params)
|
261
|
+
|
262
|
+
stream.puts "#{error.class}: #{error.message}"
|
263
|
+
resolution = self.resolution_for(error)
|
264
|
+
stream.puts "#{resolution}" if resolution
|
265
|
+
end
|
266
|
+
|
267
|
+
def write_compilation_stack(stream, error, params={})
|
268
|
+
self.write_section_header(stream, 'Compilation stack', params)
|
269
|
+
|
270
|
+
if self.stack.empty?
|
271
|
+
stream.puts " (empty)"
|
272
|
+
else
|
273
|
+
self.stack.reverse.each do |obj|
|
274
|
+
if obj.is_a?(Nanoc::ItemRep)
|
275
|
+
stream.puts " - [item] #{obj.item.identifier} (rep #{obj.name})"
|
276
|
+
else # layout
|
277
|
+
stream.puts " - [layout] #{obj.identifier}"
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def write_stack_trace(stream, error, params={})
|
284
|
+
self.write_section_header(stream, 'Stack trace', params)
|
285
|
+
|
286
|
+
count = params[:verbose] ? -1 : 10
|
287
|
+
error.backtrace[0...count].each_with_index do |item, index|
|
288
|
+
stream.puts " #{index}. #{item}"
|
289
|
+
end
|
290
|
+
if error.backtrace.size > count
|
291
|
+
stream.puts " ... #{error.backtrace.size - count} more lines omitted. See full crash log for details."
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def write_issue_link(stream, params={})
|
296
|
+
stream.puts
|
297
|
+
stream.puts "If you believe this is a bug in nanoc, please do report it at"
|
298
|
+
stream.puts "-> https://github.com/ddfreyne/nanoc/issues/new <-"
|
299
|
+
stream.puts
|
300
|
+
stream.puts "A detailed crash log has been written to ./crash.log."
|
301
|
+
end
|
302
|
+
|
303
|
+
def write_version_information(stream, params={})
|
304
|
+
self.write_section_header(stream, 'Version information', params)
|
305
|
+
stream.puts Nanoc.version_information
|
306
|
+
end
|
307
|
+
|
308
|
+
def write_system_information(stream, params={})
|
309
|
+
begin
|
310
|
+
uname = `uname -a`
|
311
|
+
self.write_section_header(stream, 'System information', params)
|
312
|
+
stream.puts uname
|
313
|
+
rescue Errno::ENOENT
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def write_installed_gems(stream, params={})
|
318
|
+
self.write_section_header(stream, 'Installed gems', params)
|
319
|
+
self.gems_and_versions.each do |g|
|
320
|
+
stream.puts " #{g.first} #{g.last.join(', ')}"
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def write_environment(stream, params={})
|
325
|
+
self.write_section_header(stream, 'Environment', params)
|
326
|
+
ENV.sort.each do |e|
|
327
|
+
stream.puts "#{e.first} => #{e.last.inspect}"
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def write_gemfile_lock(stream, params={})
|
332
|
+
if File.exist?('Gemfile.lock')
|
333
|
+
self.write_section_header(stream, 'Gemfile.lock', params)
|
334
|
+
stream.puts File.read('Gemfile.lock')
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def write_load_paths(stream, params={})
|
339
|
+
self.write_section_header(stream, 'Load paths', params)
|
340
|
+
$LOAD_PATH.each_with_index do |i, index|
|
341
|
+
stream.puts " #{index}. #{i}"
|
342
|
+
end
|
343
343
|
end
|
344
344
|
|
345
345
|
end
|