nanoc3 3.1.9 → 3.2.0a1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/NEWS.md +0 -50
- data/README.md +3 -15
- data/bin/nanoc3 +2 -0
- data/lib/nanoc3/base/checksummer.rb +40 -0
- data/lib/nanoc3/base/code_snippet.rb +30 -12
- data/lib/nanoc3/base/compiled_content_cache.rb +86 -0
- data/lib/nanoc3/base/compiler.rb +134 -95
- data/lib/nanoc3/base/compiler_dsl.rb +12 -11
- data/lib/nanoc3/base/core_ext/string.rb +2 -2
- data/lib/nanoc3/base/data_source.rb +17 -16
- data/lib/nanoc3/base/dependency_tracker.rb +102 -121
- data/lib/nanoc3/base/directed_graph.rb +65 -3
- data/lib/nanoc3/base/errors.rb +20 -16
- data/lib/nanoc3/base/item.rb +58 -50
- data/lib/nanoc3/base/item_rep.rb +177 -150
- data/lib/nanoc3/base/layout.rb +51 -18
- data/lib/nanoc3/base/notification_center.rb +8 -8
- data/lib/nanoc3/base/plugin_registry.rb +9 -9
- data/lib/nanoc3/base/rule.rb +18 -9
- data/lib/nanoc3/base/rule_context.rb +5 -5
- data/lib/nanoc3/base/site.rb +135 -47
- data/lib/nanoc3/base.rb +21 -19
- data/lib/nanoc3/cli/base.rb +51 -74
- data/lib/nanoc3/cli/commands/autocompile.rb +3 -0
- data/lib/nanoc3/cli/commands/compile.rb +35 -74
- data/lib/nanoc3/cli/commands/create_site.rb +17 -5
- data/lib/nanoc3/cli/commands/debug.rb +11 -4
- data/lib/nanoc3/cli/commands/view.rb +0 -1
- data/lib/nanoc3/cli/commands/watch.rb +148 -0
- data/lib/nanoc3/cli/commands.rb +1 -0
- data/lib/nanoc3/cli/logger.rb +15 -21
- data/lib/nanoc3/data_sources/deprecated/twitter.rb +0 -1
- data/lib/nanoc3/data_sources/filesystem.rb +11 -40
- data/lib/nanoc3/data_sources/filesystem_unified.rb +22 -22
- data/lib/nanoc3/extra/auto_compiler.rb +1 -1
- data/lib/nanoc3/extra/chick.rb +8 -8
- data/lib/nanoc3/extra/deployers/rsync.rb +2 -3
- data/lib/nanoc3/extra/validators/links.rb +32 -51
- data/lib/nanoc3/extra/validators/w3c.rb +2 -2
- data/lib/nanoc3/extra/vcs.rb +1 -1
- data/lib/nanoc3/filters/colorize_syntax.rb +15 -19
- data/lib/nanoc3/filters/erb.rb +1 -5
- data/lib/nanoc3/filters/erubis.rb +1 -5
- data/lib/nanoc3/filters/haml.rb +1 -2
- data/lib/nanoc3/filters/less.rb +2 -51
- data/lib/nanoc3/filters/mustache.rb +21 -0
- data/lib/nanoc3/filters/rdiscount.rb +1 -2
- data/lib/nanoc3/filters/relativize_paths.rb +3 -2
- data/lib/nanoc3/filters/sass.rb +50 -56
- data/lib/nanoc3/filters.rb +2 -0
- data/lib/nanoc3/helpers/blogging.rb +22 -29
- data/lib/nanoc3/helpers/breadcrumbs.rb +1 -1
- data/lib/nanoc3/helpers/capturing.rb +1 -1
- data/lib/nanoc3/helpers/filtering.rb +1 -1
- data/lib/nanoc3/helpers/link_to.rb +10 -21
- data/lib/nanoc3/helpers/rendering.rb +5 -24
- data/lib/nanoc3/helpers/tagging.rb +6 -6
- data/lib/nanoc3/helpers/text.rb +2 -2
- data/lib/nanoc3.rb +1 -1
- metadata +35 -93
- data/.gemtest +0 -0
- data/doc/yardoc_templates/default/layout/html/footer.erb +0 -10
- data/nanoc3.gemspec +0 -41
- data/tasks/clean.rake +0 -11
- data/tasks/doc.rake +0 -14
- data/tasks/gem.rake +0 -13
- data/tasks/test.rake +0 -38
- data/test/base/core_ext/array_spec.rb +0 -23
- data/test/base/core_ext/hash_spec.rb +0 -41
- data/test/base/core_ext/string_spec.rb +0 -27
- data/test/base/test_code_snippet.rb +0 -33
- data/test/base/test_compiler.rb +0 -410
- data/test/base/test_compiler_dsl.rb +0 -121
- data/test/base/test_context.rb +0 -33
- data/test/base/test_data_source.rb +0 -48
- data/test/base/test_dependency_tracker.rb +0 -510
- data/test/base/test_directed_graph.rb +0 -91
- data/test/base/test_filter.rb +0 -85
- data/test/base/test_item.rb +0 -141
- data/test/base/test_item_rep.rb +0 -953
- data/test/base/test_layout.rb +0 -44
- data/test/base/test_notification_center.rb +0 -36
- data/test/base/test_plugin.rb +0 -32
- data/test/base/test_rule.rb +0 -21
- data/test/base/test_rule_context.rb +0 -63
- data/test/base/test_site.rb +0 -366
- data/test/cli/commands/test_compile.rb +0 -12
- data/test/cli/commands/test_create_item.rb +0 -12
- data/test/cli/commands/test_create_layout.rb +0 -28
- data/test/cli/commands/test_create_site.rb +0 -24
- data/test/cli/commands/test_help.rb +0 -12
- data/test/cli/commands/test_info.rb +0 -12
- data/test/cli/commands/test_update.rb +0 -12
- data/test/cli/test_logger.rb +0 -12
- data/test/data_sources/test_filesystem.rb +0 -420
- data/test/data_sources/test_filesystem_unified.rb +0 -538
- data/test/data_sources/test_filesystem_verbose.rb +0 -359
- data/test/extra/core_ext/test_enumerable.rb +0 -32
- data/test/extra/core_ext/test_time.rb +0 -17
- data/test/extra/deployers/test_rsync.rb +0 -234
- data/test/extra/test_auto_compiler.rb +0 -482
- data/test/extra/test_file_proxy.rb +0 -21
- data/test/extra/test_vcs.rb +0 -24
- data/test/extra/validators/test_links.rb +0 -53
- data/test/extra/validators/test_w3c.rb +0 -49
- data/test/filters/test_bluecloth.rb +0 -20
- data/test/filters/test_coderay.rb +0 -46
- data/test/filters/test_colorize_syntax.rb +0 -84
- data/test/filters/test_erb.rb +0 -72
- data/test/filters/test_erubis.rb +0 -72
- data/test/filters/test_haml.rb +0 -98
- data/test/filters/test_kramdown.rb +0 -20
- data/test/filters/test_less.rb +0 -118
- data/test/filters/test_markaby.rb +0 -26
- data/test/filters/test_maruku.rb +0 -20
- data/test/filters/test_rainpress.rb +0 -31
- data/test/filters/test_rdiscount.rb +0 -33
- data/test/filters/test_rdoc.rb +0 -18
- data/test/filters/test_redcloth.rb +0 -20
- data/test/filters/test_relativize_paths.rb +0 -231
- data/test/filters/test_rubypants.rb +0 -20
- data/test/filters/test_sass.rb +0 -235
- data/test/gem_loader.rb +0 -11
- data/test/helper.rb +0 -99
- data/test/helpers/test_blogging.rb +0 -808
- data/test/helpers/test_breadcrumbs.rb +0 -83
- data/test/helpers/test_capturing.rb +0 -42
- data/test/helpers/test_filtering.rb +0 -108
- data/test/helpers/test_html_escape.rb +0 -18
- data/test/helpers/test_link_to.rb +0 -251
- data/test/helpers/test_rendering.rb +0 -109
- data/test/helpers/test_tagging.rb +0 -89
- data/test/helpers/test_text.rb +0 -26
- data/test/helpers/test_xml_sitemap.rb +0 -69
- data/test/tasks/test_clean.rb +0 -71
data/lib/nanoc3/cli/base.rb
CHANGED
@@ -4,9 +4,39 @@ module Nanoc3::CLI
|
|
4
4
|
|
5
5
|
class Base < Cri::Base
|
6
6
|
|
7
|
+
# A hash that contains the name of the gem for a given required file. If a
|
8
|
+
# {#require} fails, the gem name is looked up in this hash.
|
9
|
+
GEM_NAMES = {
|
10
|
+
'adsf' => 'adsf',
|
11
|
+
'bluecloth' => 'bluecloth',
|
12
|
+
'builder' => 'builder',
|
13
|
+
'coderay' => 'coderay',
|
14
|
+
'cri' => 'cri',
|
15
|
+
'erubis' => 'erubis',
|
16
|
+
'fssm' => 'fssm',
|
17
|
+
'haml' => 'haml',
|
18
|
+
'json' => 'json',
|
19
|
+
'kramdown' => 'kramdown',
|
20
|
+
'less' => 'less',
|
21
|
+
'markaby' => 'markaby',
|
22
|
+
'maruku' => 'maruku',
|
23
|
+
'mime/types' => 'mime-types',
|
24
|
+
'nokogiri' => 'nokogiri',
|
25
|
+
'rack' => 'rack',
|
26
|
+
'rack/cache' => 'rack-cache',
|
27
|
+
'rainpress' => 'rainpress',
|
28
|
+
'rdiscount' => 'rdiscount',
|
29
|
+
'redcloth' => 'redcloth',
|
30
|
+
'rubypants' => 'rubypants',
|
31
|
+
'sass' => 'sass',
|
32
|
+
'w3c_validators' => 'w3c_validators'
|
33
|
+
}
|
34
|
+
|
7
35
|
def initialize
|
8
36
|
super('nanoc3')
|
9
37
|
|
38
|
+
@debug = false
|
39
|
+
|
10
40
|
# Add help command
|
11
41
|
self.help_command = Nanoc3::CLI::Commands::Help.new
|
12
42
|
add_command(self.help_command)
|
@@ -21,22 +51,20 @@ module Nanoc3::CLI
|
|
21
51
|
add_command(Nanoc3::CLI::Commands::Info.new)
|
22
52
|
add_command(Nanoc3::CLI::Commands::Update.new)
|
23
53
|
add_command(Nanoc3::CLI::Commands::View.new)
|
54
|
+
add_command(Nanoc3::CLI::Commands::Watch.new)
|
24
55
|
end
|
25
56
|
|
26
|
-
# Returns a fully initialised base instance. It is recommended to use this
|
27
|
-
# shared instance than to create new ones, as this will be the instance
|
28
|
-
# that will be used when reading all code from the `lib/` directory.
|
29
|
-
#
|
30
|
-
# @return [Nanoc3::CLI::Base]
|
31
57
|
def self.shared_base
|
32
58
|
@shared_base ||= Nanoc3::CLI::Base.new
|
33
59
|
end
|
34
60
|
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
61
|
+
# @return [Boolean] true if debug output is enabled, false if not
|
62
|
+
def debug?
|
63
|
+
@debug
|
64
|
+
end
|
65
|
+
|
66
|
+
# Helper function which can be called when a command is executed that
|
67
|
+
# requires a site, such as the compile command.
|
40
68
|
def require_site
|
41
69
|
if site.nil?
|
42
70
|
$stderr.puts 'The current working directory does not seem to be a ' +
|
@@ -45,10 +73,7 @@ module Nanoc3::CLI
|
|
45
73
|
end
|
46
74
|
end
|
47
75
|
|
48
|
-
# Gets the site (
|
49
|
-
# loads its data.
|
50
|
-
#
|
51
|
-
# @return [Nanoc3::Site] The site in the current working directory
|
76
|
+
# Gets the site (Nanoc3::Site) in the current directory and loads its data.
|
52
77
|
def site
|
53
78
|
# Load site if possible
|
54
79
|
if File.file?('config.yaml') && (!self.instance_variable_defined?(:@site) || @site.nil?)
|
@@ -63,16 +88,8 @@ module Nanoc3::CLI
|
|
63
88
|
@site
|
64
89
|
end
|
65
90
|
|
66
|
-
#
|
91
|
+
# Inherited from ::Cri::Base
|
67
92
|
def run(args)
|
68
|
-
# Set exit handler
|
69
|
-
[ 'INT', 'TERM' ].each do |signal|
|
70
|
-
Signal.trap(signal) do
|
71
|
-
puts
|
72
|
-
exit!(0)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
93
|
super(args)
|
77
94
|
rescue Interrupt => e
|
78
95
|
exit(1)
|
@@ -81,12 +98,8 @@ module Nanoc3::CLI
|
|
81
98
|
exit(1)
|
82
99
|
end
|
83
100
|
|
84
|
-
# Prints the given error to stderr. Includes message, possible resolution
|
85
|
-
#
|
86
|
-
#
|
87
|
-
# @param [Error] error The error that should be described
|
88
|
-
#
|
89
|
-
# @return [void]
|
101
|
+
# Prints the given error to stderr. Includes message, possible resolution,
|
102
|
+
# compilation stack, backtrace, etc.
|
90
103
|
def print_error(error)
|
91
104
|
$stderr.puts
|
92
105
|
|
@@ -130,44 +143,14 @@ module Nanoc3::CLI
|
|
130
143
|
$stderr.puts error.backtrace.to_enum(:each_with_index).map { |item, index| " #{index}. #{item}" }.join("\n")
|
131
144
|
end
|
132
145
|
|
133
|
-
#
|
134
|
-
# resolution can be automatically obtained.
|
135
|
-
#
|
136
|
-
# @param [Error] error The error to find a resolution for
|
137
|
-
#
|
138
|
-
# @return [String] The resolution for the given error
|
146
|
+
# Returns a string containing hints for resolving the given error, or nil
|
147
|
+
# if no resolution can be automatically obtained.
|
139
148
|
def resolution_for(error)
|
140
|
-
# FIXME this should probably go somewhere else so that 3rd-party code can add other gem names too
|
141
|
-
gem_names = {
|
142
|
-
'adsf' => 'adsf',
|
143
|
-
'bluecloth' => 'bluecloth',
|
144
|
-
'builder' => 'builder',
|
145
|
-
'coderay' => 'coderay',
|
146
|
-
'cri' => 'cri',
|
147
|
-
'erubis' => 'erubis',
|
148
|
-
'haml' => 'haml',
|
149
|
-
'json' => 'json',
|
150
|
-
'less' => 'less',
|
151
|
-
'markaby' => 'markaby',
|
152
|
-
'maruku' => 'maruku',
|
153
|
-
'mime/types' => 'mime-types',
|
154
|
-
'rack' => 'rack',
|
155
|
-
'rack/cache' => 'rack-cache',
|
156
|
-
'rainpress' => 'rainpress',
|
157
|
-
'rdiscount' => 'rdiscount',
|
158
|
-
'redcloth' => 'redcloth',
|
159
|
-
'rubypants' => 'rubypants',
|
160
|
-
'sass' => 'sass',
|
161
|
-
'w3c_validators' => 'w3c_validators'
|
162
|
-
}
|
163
|
-
|
164
149
|
case error
|
165
150
|
when LoadError
|
166
151
|
# Get gem name
|
167
|
-
|
168
|
-
|
169
|
-
lib_name = matches[1]
|
170
|
-
gem_name = gem_names[$1]
|
152
|
+
lib_name = error.message.match(/no such file to load -- ([^\s]+)/)[1]
|
153
|
+
gem_name = GEM_NAMES[$1]
|
171
154
|
|
172
155
|
# Build message
|
173
156
|
if gem_name
|
@@ -179,10 +162,6 @@ module Nanoc3::CLI
|
|
179
162
|
# Sets the data source's VCS to the VCS with the given name. Does nothing
|
180
163
|
# when the site's data source does not support VCSes (i.e. does not
|
181
164
|
# implement #vcs=).
|
182
|
-
#
|
183
|
-
# @param [String] vcs_name The name of the VCS that should be used
|
184
|
-
#
|
185
|
-
# @return [void]
|
186
165
|
def set_vcs(vcs_name)
|
187
166
|
# Skip if not possible
|
188
167
|
return if vcs_name.nil? || site.nil?
|
@@ -203,7 +182,7 @@ module Nanoc3::CLI
|
|
203
182
|
end
|
204
183
|
end
|
205
184
|
|
206
|
-
#
|
185
|
+
# Returns the list of global option definitionss.
|
207
186
|
def global_option_definitions
|
208
187
|
[
|
209
188
|
{
|
@@ -224,7 +203,7 @@ module Nanoc3::CLI
|
|
224
203
|
},
|
225
204
|
{
|
226
205
|
:long => 'debug', :short => 'd', :argument => :forbidden,
|
227
|
-
:desc => 'enable debugging
|
206
|
+
:desc => 'enable debugging'
|
228
207
|
},
|
229
208
|
{
|
230
209
|
:long => 'warn', :short => 'w', :argument => :forbidden,
|
@@ -233,20 +212,18 @@ module Nanoc3::CLI
|
|
233
212
|
]
|
234
213
|
end
|
235
214
|
|
236
|
-
# @see Cri::Base#handle_option
|
237
215
|
def handle_option(option)
|
238
216
|
case option
|
239
217
|
when :version
|
240
218
|
gem_info = defined?(Gem) ? "with RubyGems #{Gem::VERSION}" : "without RubyGems"
|
241
|
-
engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
|
242
219
|
|
243
|
-
puts "nanoc #{Nanoc3::VERSION} (c) 2007-
|
244
|
-
puts "
|
220
|
+
puts "nanoc #{Nanoc3::VERSION} (c) 2007-2010 Denis Defreyne."
|
221
|
+
puts "Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) running on #{RUBY_PLATFORM} #{gem_info}"
|
245
222
|
exit 0
|
246
223
|
when :verbose
|
247
224
|
Nanoc3::CLI::Logger.instance.level = :low
|
248
225
|
when :debug
|
249
|
-
|
226
|
+
@debug = true
|
250
227
|
when :warn
|
251
228
|
$-w = true
|
252
229
|
when :'no-color'
|
@@ -49,6 +49,9 @@ module Nanoc3::CLI::Commands
|
|
49
49
|
def run(options, arguments)
|
50
50
|
require 'rack'
|
51
51
|
|
52
|
+
# Warn
|
53
|
+
warn 'WARNING: As of nanoc 3.2, the autocompiler is deprecated. Consider using the new and much faster “nanoc watch” command that recompiles the site on change rather than on request.'
|
54
|
+
|
52
55
|
# Make sure we are in a nanoc site directory
|
53
56
|
@base.require_site
|
54
57
|
|
@@ -76,8 +76,8 @@ module Nanoc3::CLI::Commands
|
|
76
76
|
|
77
77
|
# Initialize profiling stuff
|
78
78
|
time_before = Time.now
|
79
|
-
@
|
80
|
-
@
|
79
|
+
@rep_times = {}
|
80
|
+
@filter_times = {}
|
81
81
|
setup_notifications
|
82
82
|
|
83
83
|
# Compile
|
@@ -91,9 +91,11 @@ module Nanoc3::CLI::Commands
|
|
91
91
|
|
92
92
|
# Show skipped reps
|
93
93
|
reps.select { |r| !r.compiled? }.each do |rep|
|
94
|
-
|
95
|
-
|
96
|
-
|
94
|
+
rep.raw_paths.each do |snapshot_name, filename|
|
95
|
+
next if filename.nil?
|
96
|
+
duration = @rep_times[filename]
|
97
|
+
Nanoc3::CLI::Logger.instance.file(:high, :skip, filename, duration)
|
98
|
+
end
|
97
99
|
end
|
98
100
|
|
99
101
|
# Show diff
|
@@ -101,11 +103,10 @@ module Nanoc3::CLI::Commands
|
|
101
103
|
|
102
104
|
# Give general feedback
|
103
105
|
puts
|
104
|
-
puts "No items were modified." unless reps.any? { |r| r.modified? }
|
105
106
|
puts "#{item.nil? ? 'Site' : 'Item'} compiled in #{format('%.2f', Time.now - time_before)}s."
|
106
107
|
|
108
|
+
# Give detailed feedback
|
107
109
|
if options.has_key?(:verbose)
|
108
|
-
print_state_feedback(reps)
|
109
110
|
print_profiling_feedback(reps)
|
110
111
|
end
|
111
112
|
end
|
@@ -113,17 +114,39 @@ module Nanoc3::CLI::Commands
|
|
113
114
|
private
|
114
115
|
|
115
116
|
def setup_notifications
|
117
|
+
# File notifications
|
118
|
+
Nanoc3::NotificationCenter.on(:rep_written) do |rep, path, is_created, is_modified|
|
119
|
+
action = (is_created ? :create : (is_modified ? :update : :identical))
|
120
|
+
duration = Time.now - @rep_times[rep.raw_path] if @rep_times[rep.raw_path]
|
121
|
+
Nanoc3::CLI::Logger.instance.file(:high, action, path, duration)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Debug notifications
|
116
125
|
Nanoc3::NotificationCenter.on(:compilation_started) do |rep|
|
117
|
-
|
126
|
+
puts "*** Started compilation of #{rep.inspect}" if @base.debug?
|
118
127
|
end
|
119
128
|
Nanoc3::NotificationCenter.on(:compilation_ended) do |rep|
|
120
|
-
|
129
|
+
puts "*** Ended compilation of #{rep.inspect}" if @base.debug?
|
130
|
+
end
|
131
|
+
Nanoc3::NotificationCenter.on(:compilation_failed) do |rep|
|
132
|
+
puts "*** Suspended compilation of #{rep.inspect} due to unmet dependencies" if @base.debug?
|
133
|
+
end
|
134
|
+
Nanoc3::NotificationCenter.on(:cached_content_used) do |rep|
|
135
|
+
puts "*** Used cached compiled content for #{rep.inspect} instead of recompiling" if @base.debug?
|
136
|
+
end
|
137
|
+
|
138
|
+
# Timing notifications
|
139
|
+
Nanoc3::NotificationCenter.on(:compilation_started) do |rep|
|
140
|
+
@rep_times[rep.raw_path] = Time.now
|
141
|
+
end
|
142
|
+
Nanoc3::NotificationCenter.on(:compilation_ended) do |rep|
|
143
|
+
@rep_times[rep.raw_path] = Time.now - @rep_times[rep.raw_path]
|
121
144
|
end
|
122
145
|
Nanoc3::NotificationCenter.on(:filtering_started) do |rep, filter_name|
|
123
|
-
|
146
|
+
@filter_times[filter_name] = Time.now
|
124
147
|
end
|
125
148
|
Nanoc3::NotificationCenter.on(:filtering_ended) do |rep, filter_name|
|
126
|
-
|
149
|
+
@filter_times[filter_name] = Time.now - @filter_times[filter_name]
|
127
150
|
end
|
128
151
|
end
|
129
152
|
|
@@ -141,6 +164,7 @@ module Nanoc3::CLI::Commands
|
|
141
164
|
next if diff.nil?
|
142
165
|
|
143
166
|
# Fix header
|
167
|
+
# FIXME this may break for other lines starting with --- or +++
|
144
168
|
diff.sub!(/^--- .*/, '--- ' + rep.raw_path)
|
145
169
|
diff.sub!(/^\+\+\+ .*/, '+++ ' + rep.raw_path)
|
146
170
|
|
@@ -152,24 +176,6 @@ module Nanoc3::CLI::Commands
|
|
152
176
|
File.open('output.diff', 'w') { |io| io.write(full_diff) }
|
153
177
|
end
|
154
178
|
|
155
|
-
def print_state_feedback(reps)
|
156
|
-
# Categorise reps
|
157
|
-
rest = reps
|
158
|
-
created, rest = *rest.partition { |r| r.created? }
|
159
|
-
modified, rest = *rest.partition { |r| r.modified? }
|
160
|
-
skipped, rest = *rest.partition { |r| !r.compiled? }
|
161
|
-
not_written, rest = *rest.partition { |r| r.compiled? && !r.written? }
|
162
|
-
identical = rest
|
163
|
-
|
164
|
-
# Print
|
165
|
-
puts
|
166
|
-
puts format(' %4d created', created.size)
|
167
|
-
puts format(' %4d modified', modified.size)
|
168
|
-
puts format(' %4d skipped', skipped.size)
|
169
|
-
puts format(' %4d not written', not_written.size)
|
170
|
-
puts format(' %4d identical', identical.size)
|
171
|
-
end
|
172
|
-
|
173
179
|
def print_profiling_feedback(reps)
|
174
180
|
# Get max filter length
|
175
181
|
max_filter_name_length = @filter_times.keys.map { |k| k.to_s.size }.max
|
@@ -211,51 +217,6 @@ module Nanoc3::CLI::Commands
|
|
211
217
|
end
|
212
218
|
end
|
213
219
|
|
214
|
-
def rep_compilation_started(rep)
|
215
|
-
# Profile compilation
|
216
|
-
@rep_times ||= {}
|
217
|
-
@rep_times[rep.raw_path] = Time.now
|
218
|
-
end
|
219
|
-
|
220
|
-
def rep_compilation_ended(rep)
|
221
|
-
# Profile compilation
|
222
|
-
@rep_times ||= {}
|
223
|
-
@rep_times[rep.raw_path] = Time.now - @rep_times[rep.raw_path]
|
224
|
-
|
225
|
-
# Skip if not outputted
|
226
|
-
return unless rep.written?
|
227
|
-
|
228
|
-
# Get action and level
|
229
|
-
action = if rep.created?
|
230
|
-
:create
|
231
|
-
elsif rep.modified?
|
232
|
-
:update
|
233
|
-
elsif !rep.compiled?
|
234
|
-
nil
|
235
|
-
else
|
236
|
-
:identical
|
237
|
-
end
|
238
|
-
|
239
|
-
# Log
|
240
|
-
unless action.nil?
|
241
|
-
duration = @rep_times[rep.raw_path]
|
242
|
-
Nanoc3::CLI::Logger.instance.file(:high, action, rep.raw_path, duration)
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
def rep_filtering_started(rep, filter_name)
|
247
|
-
@times_stack.push(Time.now)
|
248
|
-
end
|
249
|
-
|
250
|
-
def rep_filtering_ended(rep, filter_name)
|
251
|
-
# Get last time
|
252
|
-
time_start = @times_stack.pop
|
253
|
-
|
254
|
-
# Update times
|
255
|
-
@filter_times[filter_name.to_sym] ||= []
|
256
|
-
@filter_times[filter_name.to_sym] << Time.now - time_start
|
257
|
-
end
|
258
|
-
|
259
220
|
end
|
260
221
|
|
261
222
|
end
|
@@ -57,6 +57,20 @@ data_sources:
|
|
57
57
|
# The path where layouts should be mounted. The layouts root behaves the
|
58
58
|
# same as the items root, but applies to layouts rather than items.
|
59
59
|
layouts_root: #{Nanoc3::Site::DEFAULT_DATA_SOURCE_CONFIG[:layouts_root]}
|
60
|
+
|
61
|
+
# Configuration for the “watch” command, which watches a site for changes and
|
62
|
+
# recompiles if necessary.
|
63
|
+
watcher:
|
64
|
+
# A list of directories to watch for changes. When editing this, make sure
|
65
|
+
# that the “output/” and “tmp/” directories are _not_ included in this list,
|
66
|
+
# because recompiling the site will cause these directories to change, which
|
67
|
+
# will cause the site to be recompiled, which will cause these directories
|
68
|
+
# to change, which will cause the site to be recompiled again, and so on.
|
69
|
+
dirs_to_watch: [ 'content', 'layouts', 'lib' ]
|
70
|
+
|
71
|
+
# A list of single files to watch for changes. As mentioned above, don’t put
|
72
|
+
# any files from the “output/” or “tmp/” directories in here.
|
73
|
+
files_to_watch: [ 'config.yaml', 'Rules' ]
|
60
74
|
EOS
|
61
75
|
|
62
76
|
DEFAULT_RULES = <<EOS
|
@@ -156,20 +170,18 @@ a:hover {
|
|
156
170
|
line-height: 20px;
|
157
171
|
}
|
158
172
|
|
159
|
-
#main ul
|
173
|
+
#main ul {
|
160
174
|
margin: 20px;
|
161
175
|
}
|
162
176
|
|
163
177
|
#main li {
|
178
|
+
list-style-type: square;
|
179
|
+
|
164
180
|
font-size: 15px;
|
165
181
|
|
166
182
|
line-height: 20px;
|
167
183
|
}
|
168
184
|
|
169
|
-
#main ul li {
|
170
|
-
list-style-type: square;
|
171
|
-
}
|
172
|
-
|
173
185
|
#sidebar {
|
174
186
|
position: absolute;
|
175
187
|
|
@@ -43,8 +43,7 @@ module Nanoc3::CLI::Commands
|
|
43
43
|
layouts = @base.site.layouts
|
44
44
|
|
45
45
|
# Get dependency tracker
|
46
|
-
|
47
|
-
dependency_tracker = @base.site.compiler.send(:dependency_tracker)
|
46
|
+
dependency_tracker = @base.site.compiler.dependency_tracker
|
48
47
|
dependency_tracker.load_graph
|
49
48
|
|
50
49
|
# Print item dependencies
|
@@ -66,7 +65,13 @@ module Nanoc3::CLI::Commands
|
|
66
65
|
items.sort_by { |i| i.identifier }.each do |item|
|
67
66
|
item.reps.sort_by { |r| r.name.to_s }.each do |rep|
|
68
67
|
puts "item #{item.identifier}, rep #{rep.name}:"
|
69
|
-
|
68
|
+
if rep.raw_paths.empty?
|
69
|
+
puts " (not written)"
|
70
|
+
end
|
71
|
+
length = rep.raw_paths.keys.map { |s| s.to_s.length }.max
|
72
|
+
rep.raw_paths.each do |snapshot_name, raw_path|
|
73
|
+
puts " [ %-#{length}s ] %s" % [ snapshot_name, raw_path ]
|
74
|
+
end
|
70
75
|
end
|
71
76
|
puts
|
72
77
|
end
|
@@ -91,7 +96,9 @@ module Nanoc3::CLI::Commands
|
|
91
96
|
puts '=== Layouts'
|
92
97
|
puts
|
93
98
|
layouts.each do |layout|
|
94
|
-
puts "layout #{layout.identifier}"
|
99
|
+
puts "layout #{layout.identifier}:"
|
100
|
+
puts " is #{layout.outdated? ? '' : 'not '}outdated"
|
101
|
+
puts
|
95
102
|
end
|
96
103
|
end
|
97
104
|
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3::CLI::Commands
|
4
|
+
|
5
|
+
class Watch < Cri::Command
|
6
|
+
|
7
|
+
def name
|
8
|
+
'watch'
|
9
|
+
end
|
10
|
+
|
11
|
+
def aliases
|
12
|
+
[ ]
|
13
|
+
end
|
14
|
+
|
15
|
+
def short_desc
|
16
|
+
'start the watcher'
|
17
|
+
end
|
18
|
+
|
19
|
+
def long_desc
|
20
|
+
'Start the watcher. When a change is detected, the site will be ' \
|
21
|
+
'recompiled.'
|
22
|
+
end
|
23
|
+
|
24
|
+
def usage
|
25
|
+
"nanoc3 watch"
|
26
|
+
end
|
27
|
+
|
28
|
+
def option_definitions
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
|
32
|
+
def run(options, arguments)
|
33
|
+
require 'fssm'
|
34
|
+
|
35
|
+
@notifier = Notifier.new
|
36
|
+
|
37
|
+
# Define rebuilder
|
38
|
+
rebuilder = lambda do |base, relative|
|
39
|
+
# Determine filename
|
40
|
+
if base.nil? || relative.nil?
|
41
|
+
filename = nil
|
42
|
+
else
|
43
|
+
filename = ::Pathname.new(File.join([ base, relative ])).relative_path_from(::Pathname.new(Dir.getwd)).to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
# Notify
|
47
|
+
if filename
|
48
|
+
print "Change detected to #{filename}; recompiling… ".make_compatible_with_env
|
49
|
+
else
|
50
|
+
print "Watcher started; compiling the entire site… ".make_compatible_with_env
|
51
|
+
end
|
52
|
+
|
53
|
+
# Recompile
|
54
|
+
start = Time.now
|
55
|
+
site = Nanoc3::Site.new('.')
|
56
|
+
site.load_data
|
57
|
+
begin
|
58
|
+
site.compiler.run
|
59
|
+
|
60
|
+
# TODO include icon (--image misc/success-icon.png)
|
61
|
+
@notifier.notify('Compilation complete')
|
62
|
+
|
63
|
+
puts "done in #{((Time.now - start)*10000).round.to_f / 10}ms"
|
64
|
+
rescue Exception => e
|
65
|
+
# TODO include icon (--image misc/error-icon.png)
|
66
|
+
@notifier.notify('Compilation failed')
|
67
|
+
|
68
|
+
puts
|
69
|
+
@base.print_error(e)
|
70
|
+
puts
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Rebuild once
|
75
|
+
rebuilder.call(nil, nil)
|
76
|
+
|
77
|
+
# Get directories to watch
|
78
|
+
watcher_config = @base.site.config[:watcher] || {}
|
79
|
+
dirs_to_watch = watcher_config[:dirs_to_watch] || %w( content layouts lib )
|
80
|
+
files_to_watch = watcher_config[:files_to_watch] || %w( config.yaml Rules )
|
81
|
+
|
82
|
+
# Watch
|
83
|
+
puts "Watching for changes…".make_compatible_with_env
|
84
|
+
watcher = lambda do
|
85
|
+
update(&rebuilder)
|
86
|
+
delete(&rebuilder)
|
87
|
+
create(&rebuilder)
|
88
|
+
end
|
89
|
+
monitor = FSSM::Monitor.new
|
90
|
+
dirs_to_watch.each { |dir| monitor.path(dir, '**/*', &watcher) }
|
91
|
+
files_to_watch.each { |filename| monitor.file(filename, &watcher) }
|
92
|
+
monitor.run
|
93
|
+
end
|
94
|
+
|
95
|
+
# Allows sending user notifications in a cross-platform way.
|
96
|
+
class Notifier
|
97
|
+
|
98
|
+
# A list of commandline tool names that can be used to send notifications
|
99
|
+
TOOLS = %w( growlnotify notify_send )
|
100
|
+
|
101
|
+
# Error that is raised when no notifier can be found.
|
102
|
+
class NoNotifierFound < ::StandardError
|
103
|
+
|
104
|
+
def initialize
|
105
|
+
super("Could not find a notifier that works on this system. I tried to find #{CrossPlatformNotifier::TOOLS.join(', ')} but found nothing.")
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
# Send a notification.
|
111
|
+
#
|
112
|
+
# @param [String] message The message to include in the notification
|
113
|
+
#
|
114
|
+
# @option params [Boolean] :raise (true) true if this method should
|
115
|
+
# raise an exception if no notifier can be found, false otherwise
|
116
|
+
def notify(message, params={})
|
117
|
+
params[:raise] = true if !params.has_key?(:raise)
|
118
|
+
|
119
|
+
if tool.nil?
|
120
|
+
if params[:raise]
|
121
|
+
raise NoNotifierFound
|
122
|
+
else
|
123
|
+
return
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
send(tool, message, params)
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def tool
|
133
|
+
@tool ||= TOOLS.find { |t| !`which #{t}`.empty? }
|
134
|
+
end
|
135
|
+
|
136
|
+
def growlnotify(message, params={})
|
137
|
+
system('growlnotify', '-m', message)
|
138
|
+
end
|
139
|
+
|
140
|
+
def notify_send(message, params={})
|
141
|
+
system('notify_send', messsage)
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
data/lib/nanoc3/cli/commands.rb
CHANGED