nanoc 3.2.4 → 3.3.0
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/.gemtest +0 -0
- data/ChangeLog +3 -0
- data/Gemfile +32 -0
- data/LICENSE +19 -0
- data/NEWS.md +470 -0
- data/README.md +114 -0
- data/Rakefile +14 -0
- data/bin/nanoc +7 -27
- data/bin/nanoc3 +3 -0
- data/doc/yardoc_templates/default/layout/html/footer.erb +10 -0
- data/lib/nanoc.rb +41 -0
- data/lib/nanoc/base.rb +49 -0
- data/lib/nanoc/base/compilation/checksum_store.rb +57 -0
- data/lib/nanoc/base/compilation/compiled_content_cache.rb +62 -0
- data/lib/nanoc/base/compilation/compiler.rb +458 -0
- data/lib/nanoc/base/compilation/compiler_dsl.rb +214 -0
- data/lib/nanoc/base/compilation/dependency_tracker.rb +200 -0
- data/lib/nanoc/base/compilation/filter.rb +165 -0
- data/lib/nanoc/base/compilation/item_rep_proxy.rb +103 -0
- data/lib/nanoc/base/compilation/item_rep_recorder_proxy.rb +102 -0
- data/lib/nanoc/base/compilation/outdatedness_checker.rb +223 -0
- data/lib/nanoc/base/compilation/outdatedness_reasons.rb +46 -0
- data/lib/nanoc/base/compilation/rule.rb +73 -0
- data/lib/nanoc/base/compilation/rule_context.rb +84 -0
- data/lib/nanoc/base/compilation/rule_memory_calculator.rb +40 -0
- data/lib/nanoc/base/compilation/rule_memory_store.rb +53 -0
- data/lib/nanoc/base/compilation/rules_collection.rb +243 -0
- data/lib/nanoc/base/context.rb +47 -0
- data/lib/nanoc/base/core_ext.rb +6 -0
- data/lib/nanoc/base/core_ext/array.rb +62 -0
- data/lib/nanoc/base/core_ext/hash.rb +63 -0
- data/lib/nanoc/base/core_ext/pathname.rb +26 -0
- data/lib/nanoc/base/core_ext/string.rb +46 -0
- data/lib/nanoc/base/directed_graph.rb +275 -0
- data/lib/nanoc/base/errors.rb +211 -0
- data/lib/nanoc/base/memoization.rb +67 -0
- data/lib/nanoc/base/notification_center.rb +84 -0
- data/lib/nanoc/base/ordered_hash.rb +200 -0
- data/lib/nanoc/base/plugin_registry.rb +181 -0
- data/lib/nanoc/base/result_data/item_rep.rb +492 -0
- data/lib/nanoc/base/source_data/code_snippet.rb +58 -0
- data/lib/nanoc/base/source_data/configuration.rb +24 -0
- data/lib/nanoc/base/source_data/data_source.rb +234 -0
- data/lib/nanoc/base/source_data/item.rb +301 -0
- data/lib/nanoc/base/source_data/layout.rb +130 -0
- data/lib/nanoc/base/source_data/site.rb +361 -0
- data/lib/nanoc/base/store.rb +135 -0
- data/lib/nanoc/cli.rb +137 -0
- data/lib/nanoc/cli/command_runner.rb +104 -0
- data/lib/nanoc/cli/commands/autocompile.rb +58 -0
- data/lib/nanoc/cli/commands/compile.rb +297 -0
- data/lib/nanoc/cli/commands/create_item.rb +60 -0
- data/lib/nanoc/cli/commands/create_layout.rb +73 -0
- data/lib/nanoc/cli/commands/create_site.rb +411 -0
- data/lib/nanoc/cli/commands/debug.rb +117 -0
- data/lib/nanoc/cli/commands/deploy.rb +79 -0
- data/lib/nanoc/cli/commands/info.rb +98 -0
- data/lib/nanoc/cli/commands/nanoc.rb +38 -0
- data/lib/nanoc/cli/commands/prune.rb +50 -0
- data/lib/nanoc/cli/commands/update.rb +70 -0
- data/lib/nanoc/cli/commands/view.rb +82 -0
- data/lib/nanoc/cli/commands/watch.rb +124 -0
- data/lib/nanoc/cli/error_handler.rb +199 -0
- data/lib/nanoc/cli/logger.rb +92 -0
- data/lib/nanoc/data_sources.rb +29 -0
- data/lib/nanoc/data_sources/deprecated/delicious.rb +42 -0
- data/lib/nanoc/data_sources/deprecated/last_fm.rb +87 -0
- data/lib/nanoc/data_sources/deprecated/twitter.rb +38 -0
- data/lib/nanoc/data_sources/filesystem.rb +299 -0
- data/lib/nanoc/data_sources/filesystem_unified.rb +121 -0
- data/lib/nanoc/data_sources/filesystem_verbose.rb +91 -0
- data/lib/nanoc/extra.rb +24 -0
- data/lib/nanoc/extra/auto_compiler.rb +103 -0
- data/lib/nanoc/extra/chick.rb +125 -0
- data/lib/nanoc/extra/core_ext.rb +6 -0
- data/lib/nanoc/extra/core_ext/enumerable.rb +33 -0
- data/lib/nanoc/extra/core_ext/pathname.rb +30 -0
- data/lib/nanoc/extra/core_ext/time.rb +19 -0
- data/lib/nanoc/extra/deployer.rb +47 -0
- data/lib/nanoc/extra/deployers.rb +15 -0
- data/lib/nanoc/extra/deployers/fog.rb +98 -0
- data/lib/nanoc/extra/deployers/rsync.rb +70 -0
- data/lib/nanoc/extra/file_proxy.rb +40 -0
- data/lib/nanoc/extra/pruner.rb +86 -0
- data/lib/nanoc/extra/validators.rb +12 -0
- data/lib/nanoc/extra/validators/links.rb +268 -0
- data/lib/nanoc/extra/validators/w3c.rb +95 -0
- data/lib/nanoc/extra/vcs.rb +66 -0
- data/lib/nanoc/extra/vcses.rb +17 -0
- data/lib/nanoc/extra/vcses/bazaar.rb +25 -0
- data/lib/nanoc/extra/vcses/dummy.rb +24 -0
- data/lib/nanoc/extra/vcses/git.rb +25 -0
- data/lib/nanoc/extra/vcses/mercurial.rb +25 -0
- data/lib/nanoc/extra/vcses/subversion.rb +25 -0
- data/lib/nanoc/filters.rb +59 -0
- data/lib/nanoc/filters/asciidoc.rb +38 -0
- data/lib/nanoc/filters/bluecloth.rb +19 -0
- data/lib/nanoc/filters/coderay.rb +21 -0
- data/lib/nanoc/filters/coffeescript.rb +20 -0
- data/lib/nanoc/filters/colorize_syntax.rb +298 -0
- data/lib/nanoc/filters/erb.rb +38 -0
- data/lib/nanoc/filters/erubis.rb +34 -0
- data/lib/nanoc/filters/haml.rb +27 -0
- data/lib/nanoc/filters/kramdown.rb +20 -0
- data/lib/nanoc/filters/less.rb +53 -0
- data/lib/nanoc/filters/markaby.rb +20 -0
- data/lib/nanoc/filters/maruku.rb +20 -0
- data/lib/nanoc/filters/mustache.rb +24 -0
- data/lib/nanoc/filters/rainpress.rb +19 -0
- data/lib/nanoc/filters/rdiscount.rb +22 -0
- data/lib/nanoc/filters/rdoc.rb +33 -0
- data/lib/nanoc/filters/redcarpet.rb +62 -0
- data/lib/nanoc/filters/redcloth.rb +47 -0
- data/lib/nanoc/filters/relativize_paths.rb +94 -0
- data/lib/nanoc/filters/rubypants.rb +20 -0
- data/lib/nanoc/filters/sass.rb +74 -0
- data/lib/nanoc/filters/slim.rb +25 -0
- data/lib/nanoc/filters/typogruby.rb +23 -0
- data/lib/nanoc/filters/uglify_js.rb +42 -0
- data/lib/nanoc/filters/xsl.rb +46 -0
- data/lib/nanoc/filters/yui_compressor.rb +23 -0
- data/lib/nanoc/helpers.rb +16 -0
- data/lib/nanoc/helpers/blogging.rb +319 -0
- data/lib/nanoc/helpers/breadcrumbs.rb +40 -0
- data/lib/nanoc/helpers/capturing.rb +138 -0
- data/lib/nanoc/helpers/filtering.rb +50 -0
- data/lib/nanoc/helpers/html_escape.rb +55 -0
- data/lib/nanoc/helpers/link_to.rb +151 -0
- data/lib/nanoc/helpers/rendering.rb +140 -0
- data/lib/nanoc/helpers/tagging.rb +71 -0
- data/lib/nanoc/helpers/text.rb +44 -0
- data/lib/nanoc/helpers/xml_sitemap.rb +76 -0
- data/lib/nanoc/tasks.rb +10 -0
- data/lib/nanoc/tasks/clean.rake +16 -0
- data/lib/nanoc/tasks/clean.rb +29 -0
- data/lib/nanoc/tasks/deploy/rsync.rake +16 -0
- data/lib/nanoc/tasks/validate.rake +92 -0
- data/nanoc.gemspec +49 -0
- data/tasks/doc.rake +16 -0
- data/tasks/test.rake +46 -0
- data/test/base/core_ext/array_spec.rb +73 -0
- data/test/base/core_ext/hash_spec.rb +98 -0
- data/test/base/core_ext/pathname_spec.rb +27 -0
- data/test/base/core_ext/string_spec.rb +37 -0
- data/test/base/test_checksum_store.rb +35 -0
- data/test/base/test_code_snippet.rb +31 -0
- data/test/base/test_compiler.rb +403 -0
- data/test/base/test_compiler_dsl.rb +161 -0
- data/test/base/test_context.rb +31 -0
- data/test/base/test_data_source.rb +46 -0
- data/test/base/test_dependency_tracker.rb +262 -0
- data/test/base/test_directed_graph.rb +288 -0
- data/test/base/test_filter.rb +83 -0
- data/test/base/test_item.rb +179 -0
- data/test/base/test_item_rep.rb +579 -0
- data/test/base/test_layout.rb +59 -0
- data/test/base/test_memoization.rb +90 -0
- data/test/base/test_notification_center.rb +34 -0
- data/test/base/test_outdatedness_checker.rb +394 -0
- data/test/base/test_plugin.rb +30 -0
- data/test/base/test_rule.rb +19 -0
- data/test/base/test_rule_context.rb +65 -0
- data/test/base/test_site.rb +190 -0
- data/test/cli/commands/test_compile.rb +33 -0
- data/test/cli/commands/test_create_item.rb +14 -0
- data/test/cli/commands/test_create_layout.rb +28 -0
- data/test/cli/commands/test_create_site.rb +24 -0
- data/test/cli/commands/test_deploy.rb +74 -0
- data/test/cli/commands/test_help.rb +12 -0
- data/test/cli/commands/test_info.rb +11 -0
- data/test/cli/commands/test_prune.rb +98 -0
- data/test/cli/commands/test_update.rb +10 -0
- data/test/cli/test_cli.rb +102 -0
- data/test/cli/test_error_handler.rb +29 -0
- data/test/cli/test_logger.rb +10 -0
- data/test/data_sources/test_filesystem.rb +433 -0
- data/test/data_sources/test_filesystem_unified.rb +536 -0
- data/test/data_sources/test_filesystem_verbose.rb +357 -0
- data/test/extra/core_ext/test_enumerable.rb +30 -0
- data/test/extra/core_ext/test_pathname.rb +17 -0
- data/test/extra/core_ext/test_time.rb +15 -0
- data/test/extra/deployers/test_fog.rb +67 -0
- data/test/extra/deployers/test_rsync.rb +100 -0
- data/test/extra/test_auto_compiler.rb +417 -0
- data/test/extra/test_file_proxy.rb +19 -0
- data/test/extra/test_vcs.rb +22 -0
- data/test/extra/validators/test_links.rb +62 -0
- data/test/extra/validators/test_w3c.rb +47 -0
- data/test/filters/test_asciidoc.rb +22 -0
- data/test/filters/test_bluecloth.rb +18 -0
- data/test/filters/test_coderay.rb +44 -0
- data/test/filters/test_coffeescript.rb +18 -0
- data/test/filters/test_colorize_syntax.rb +379 -0
- data/test/filters/test_erb.rb +105 -0
- data/test/filters/test_erubis.rb +78 -0
- data/test/filters/test_haml.rb +96 -0
- data/test/filters/test_kramdown.rb +18 -0
- data/test/filters/test_less.rb +113 -0
- data/test/filters/test_markaby.rb +24 -0
- data/test/filters/test_maruku.rb +18 -0
- data/test/filters/test_mustache.rb +25 -0
- data/test/filters/test_rainpress.rb +29 -0
- data/test/filters/test_rdiscount.rb +31 -0
- data/test/filters/test_rdoc.rb +18 -0
- data/test/filters/test_redcarpet.rb +73 -0
- data/test/filters/test_redcloth.rb +33 -0
- data/test/filters/test_relativize_paths.rb +533 -0
- data/test/filters/test_rubypants.rb +18 -0
- data/test/filters/test_sass.rb +229 -0
- data/test/filters/test_slim.rb +35 -0
- data/test/filters/test_typogruby.rb +21 -0
- data/test/filters/test_uglify_js.rb +30 -0
- data/test/filters/test_xsl.rb +105 -0
- data/test/filters/test_yui_compressor.rb +44 -0
- data/test/gem_loader.rb +11 -0
- data/test/helper.rb +207 -0
- data/test/helpers/test_blogging.rb +754 -0
- data/test/helpers/test_breadcrumbs.rb +81 -0
- data/test/helpers/test_capturing.rb +41 -0
- data/test/helpers/test_filtering.rb +106 -0
- data/test/helpers/test_html_escape.rb +32 -0
- data/test/helpers/test_link_to.rb +249 -0
- data/test/helpers/test_rendering.rb +89 -0
- data/test/helpers/test_tagging.rb +87 -0
- data/test/helpers/test_text.rb +24 -0
- data/test/helpers/test_xml_sitemap.rb +103 -0
- data/test/tasks/test_clean.rb +67 -0
- metadata +327 -15
- data/bin/nanoc-select +0 -86
- data/lib/nanoc-select.rb +0 -11
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc
|
|
4
|
+
|
|
5
|
+
# An abstract superclass for classes that need to store data to the
|
|
6
|
+
# filesystem, such as checksums, cached compiled content and dependency
|
|
7
|
+
# graphs.
|
|
8
|
+
#
|
|
9
|
+
# Each store has a version number. When attempting to load data from a store
|
|
10
|
+
# that has an incompatible version number, no data will be loaded, but
|
|
11
|
+
# {#version_mismatch_detected} will be called.
|
|
12
|
+
#
|
|
13
|
+
# @abstract Subclasses must implement {#data} and {#data=}, and may
|
|
14
|
+
# implement {#no_data_found} and {#version_mismatch_detected}.
|
|
15
|
+
#
|
|
16
|
+
# @api private
|
|
17
|
+
class Store
|
|
18
|
+
|
|
19
|
+
# @return [String] The name of the file where data will be loaded from and
|
|
20
|
+
# stored to.
|
|
21
|
+
attr_reader :filename
|
|
22
|
+
|
|
23
|
+
# @return [Numeric] The version number corresponding to the file format
|
|
24
|
+
# the data is in. When the file format changes, the version number
|
|
25
|
+
# should be incremented.
|
|
26
|
+
attr_reader :version
|
|
27
|
+
|
|
28
|
+
# Creates a new store for the given filename.
|
|
29
|
+
#
|
|
30
|
+
# @param [String] filename The name of the file where data will be loaded
|
|
31
|
+
# from and stored to.
|
|
32
|
+
#
|
|
33
|
+
# @param [Numeric] version The version number corresponding to the file
|
|
34
|
+
# format the data is in. When the file format changes, the version
|
|
35
|
+
# number should be incremented.
|
|
36
|
+
def initialize(filename, version)
|
|
37
|
+
@filename = filename
|
|
38
|
+
@version = version
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @group Loading and storing data
|
|
42
|
+
|
|
43
|
+
# @return The data that should be written to the disk
|
|
44
|
+
#
|
|
45
|
+
# @abstract This method must be implemented by the subclass.
|
|
46
|
+
def data
|
|
47
|
+
raise NotImplementedError.new("Nanoc::Store subclasses must implement #data and #data=")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @param new_data The data that has been loaded from the disk
|
|
51
|
+
#
|
|
52
|
+
# @abstract This method must be implemented by the subclass.
|
|
53
|
+
#
|
|
54
|
+
# @return [void]
|
|
55
|
+
def data=(new_data)
|
|
56
|
+
raise NotImplementedError.new("Nanoc::Store subclasses must implement #data and #data=")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Loads the data from the filesystem into memory. This method will set the
|
|
60
|
+
# loaded data using the {#data=} method.
|
|
61
|
+
#
|
|
62
|
+
# @return [void]
|
|
63
|
+
def load
|
|
64
|
+
# Don’t load twice
|
|
65
|
+
if @loaded
|
|
66
|
+
return
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Check file existance
|
|
70
|
+
if !File.file?(self.filename)
|
|
71
|
+
no_data_found
|
|
72
|
+
@loaded = true
|
|
73
|
+
return
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
pstore.transaction do
|
|
77
|
+
# Check version
|
|
78
|
+
if pstore[:version] != self.version
|
|
79
|
+
version_mismatch_detected
|
|
80
|
+
@loaded = true
|
|
81
|
+
return
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Load
|
|
85
|
+
self.data = pstore[:data]
|
|
86
|
+
@loaded = true
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Undoes the effects of {#load}. Used when {#load} raises an exception.
|
|
91
|
+
#
|
|
92
|
+
# @api private
|
|
93
|
+
def unload
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Stores the data contained in memory to the filesystem. This method will
|
|
97
|
+
# use the {#data} method to fetch the data that should be written.
|
|
98
|
+
#
|
|
99
|
+
# @return [void]
|
|
100
|
+
def store
|
|
101
|
+
FileUtils.mkdir_p(File.dirname(self.filename))
|
|
102
|
+
|
|
103
|
+
pstore.transaction do
|
|
104
|
+
pstore[:data] = self.data
|
|
105
|
+
pstore[:version] = self.version
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @group Callback methods
|
|
110
|
+
|
|
111
|
+
# Callback method that is called when no data file was found. By default,
|
|
112
|
+
# this implementation does nothing, but it should probably be overridden
|
|
113
|
+
# by the subclass.
|
|
114
|
+
#
|
|
115
|
+
# @return [void]
|
|
116
|
+
def no_data_found
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Callback method that is called when a version mismatch is detected. By
|
|
120
|
+
# default, this implementation does nothing, but it should probably be
|
|
121
|
+
# overridden by the subclass.
|
|
122
|
+
#
|
|
123
|
+
# @return [void]
|
|
124
|
+
def version_mismatch_detected
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
def pstore
|
|
130
|
+
@pstore ||= PStore.new(self.filename)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
end
|
data/lib/nanoc/cli.rb
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'cri'
|
|
4
|
+
|
|
5
|
+
module Nanoc::CLI
|
|
6
|
+
|
|
7
|
+
module Commands
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
autoload 'Logger', 'nanoc/cli/logger'
|
|
11
|
+
autoload 'CommandRunner', 'nanoc/cli/command_runner'
|
|
12
|
+
autoload 'ErrorHandler', 'nanoc/cli/error_handler'
|
|
13
|
+
|
|
14
|
+
# Deprecated; use CommandRunner instead
|
|
15
|
+
# TODO [in nanoc 4.0] remove me
|
|
16
|
+
autoload 'Command', 'nanoc/cli/command_runner'
|
|
17
|
+
|
|
18
|
+
# @return [Boolean] true if debug output is enabled, false if not
|
|
19
|
+
#
|
|
20
|
+
# @since 3.2.0
|
|
21
|
+
def self.debug?
|
|
22
|
+
@debug || false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @param [Boolean] boolean true if debug output should be enabled,
|
|
26
|
+
# false if it should not
|
|
27
|
+
#
|
|
28
|
+
# @return [void]
|
|
29
|
+
#
|
|
30
|
+
# @since 3.2.0
|
|
31
|
+
def self.debug=(boolean)
|
|
32
|
+
@debug = boolean
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Invokes the nanoc commandline tool with the given arguments.
|
|
36
|
+
#
|
|
37
|
+
# @param [Array<String>] args An array of commandline arguments
|
|
38
|
+
#
|
|
39
|
+
# @return [void]
|
|
40
|
+
def self.run(args)
|
|
41
|
+
Nanoc::CLI::ErrorHandler.handle_while do
|
|
42
|
+
self.setup
|
|
43
|
+
self.load_custom_commands
|
|
44
|
+
self.root_command.run(args)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Adds the given command to the collection of available commands.
|
|
49
|
+
#
|
|
50
|
+
# @param [Cri::Command] cmd The command to add
|
|
51
|
+
#
|
|
52
|
+
# @return [void]
|
|
53
|
+
def self.add_command(cmd)
|
|
54
|
+
self.root_command.add_command(cmd)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
protected
|
|
58
|
+
|
|
59
|
+
# Makes the commandline interface ready for using by loading the commands.
|
|
60
|
+
#
|
|
61
|
+
# @return [void]
|
|
62
|
+
def self.setup
|
|
63
|
+
# Reinit
|
|
64
|
+
@root_command = nil
|
|
65
|
+
|
|
66
|
+
# Add help command
|
|
67
|
+
help_cmd = Cri::Command.new_basic_help
|
|
68
|
+
self.add_command(help_cmd)
|
|
69
|
+
|
|
70
|
+
# Add other commands
|
|
71
|
+
cmd_filenames = Dir[File.dirname(__FILE__) + '/cli/commands/*.rb']
|
|
72
|
+
cmd_filenames.each do |filename|
|
|
73
|
+
next if File.basename(filename, '.rb') == 'nanoc'
|
|
74
|
+
cmd = self.load_command_at(filename)
|
|
75
|
+
self.add_command(cmd)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Loads the commands in `commands/`.
|
|
80
|
+
#
|
|
81
|
+
# @return [void]
|
|
82
|
+
def self.load_custom_commands
|
|
83
|
+
self.recursive_contents_of('commands').each do |filename|
|
|
84
|
+
# Create command
|
|
85
|
+
command = Nanoc::CLI.load_command_at(filename)
|
|
86
|
+
|
|
87
|
+
# Get supercommand
|
|
88
|
+
pieces = filename.gsub(/^commands\/|\.rb$/, '').split('/')
|
|
89
|
+
pieces = pieces[0, pieces.size-1] || []
|
|
90
|
+
root = Nanoc::CLI.root_command
|
|
91
|
+
supercommand = pieces.inject(root) do |cmd, piece|
|
|
92
|
+
cmd.nil? ? nil : cmd.command_named(piece)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Add to supercommand
|
|
96
|
+
if supercommand.nil?
|
|
97
|
+
raise "Cannot load command at #{filename} because its supercommand cannot be found"
|
|
98
|
+
end
|
|
99
|
+
supercommand.add_command(command)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Loads the command in the file with the given filename.
|
|
104
|
+
#
|
|
105
|
+
# @param [String] filename The name of the file that contains the command
|
|
106
|
+
#
|
|
107
|
+
# @return [Cri::Command] The loaded command
|
|
108
|
+
def self.load_command_at(filename, command_name=nil)
|
|
109
|
+
# Load
|
|
110
|
+
code = File.read(filename)
|
|
111
|
+
cmd = Cri::Command.define(code, filename)
|
|
112
|
+
|
|
113
|
+
# Set name
|
|
114
|
+
command_name ||= File.basename(filename, '.rb')
|
|
115
|
+
cmd.modify { name command_name }
|
|
116
|
+
|
|
117
|
+
# Done
|
|
118
|
+
cmd
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# @return [Cri::Command] The root command, i.e. the commandline tool itself
|
|
122
|
+
def self.root_command
|
|
123
|
+
@root_command ||= begin
|
|
124
|
+
filename = File.dirname(__FILE__) + "/cli/commands/nanoc.rb"
|
|
125
|
+
self.load_command_at(filename)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @return [Array] The directory contents
|
|
130
|
+
def self.recursive_contents_of(path)
|
|
131
|
+
return [] unless File.directory?(path)
|
|
132
|
+
files, dirs = *Dir[path + '/*'].sort.partition { |e| File.file?(e) }
|
|
133
|
+
dirs.each { |d| files.concat self.recursive_contents_of(d) }
|
|
134
|
+
files
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Nanoc::CLI
|
|
4
|
+
|
|
5
|
+
# A command runner subclass for nanoc commands that adds nanoc-specific
|
|
6
|
+
# convenience methods and error handling.
|
|
7
|
+
class CommandRunner < ::Cri::CommandRunner
|
|
8
|
+
|
|
9
|
+
# @see http://rubydoc.info/gems/cri/Cri/CommandRunner#call-instance_method
|
|
10
|
+
#
|
|
11
|
+
# @return [void]
|
|
12
|
+
def call
|
|
13
|
+
Nanoc::CLI::ErrorHandler.handle_while(:command => self) do
|
|
14
|
+
self.run
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Gets the site ({Nanoc::Site} instance) in the current directory and
|
|
19
|
+
# loads its data.
|
|
20
|
+
#
|
|
21
|
+
# @return [Nanoc::Site] The site in the current working directory
|
|
22
|
+
def site
|
|
23
|
+
# Load site if possible
|
|
24
|
+
@site ||= nil
|
|
25
|
+
if File.file?('config.yaml') && @site.nil?
|
|
26
|
+
begin
|
|
27
|
+
@site = Nanoc::Site.new('.')
|
|
28
|
+
rescue Nanoc::Errors::UnknownDataSource => e
|
|
29
|
+
$stderr.puts "Unknown data source: #{e}"
|
|
30
|
+
exit 1
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
@site
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @deprecated use `Cri::CommandDSL#runner`
|
|
38
|
+
#
|
|
39
|
+
# @see http://rubydoc.info/gems/cri/Cri/CommandDSL#runner-instance_method
|
|
40
|
+
def self.call(opts, args, cmd)
|
|
41
|
+
self.new(opts, args, cmd).call
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
protected
|
|
45
|
+
|
|
46
|
+
# @return [Boolean] true if debug output is enabled, false if not
|
|
47
|
+
#
|
|
48
|
+
# @see Nanoc::CLI.debug?
|
|
49
|
+
def debug?
|
|
50
|
+
Nanoc::CLI.debug?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Asserts that the current working directory contains a site
|
|
54
|
+
# ({Nanoc::Site} instance). If no site is present, prints an error
|
|
55
|
+
# message and exits.
|
|
56
|
+
#
|
|
57
|
+
# @return [void]
|
|
58
|
+
def require_site
|
|
59
|
+
@site = nil
|
|
60
|
+
if site.nil?
|
|
61
|
+
$stderr.puts 'The current working directory does not seem to be a ' +
|
|
62
|
+
'valid/complete nanoc site directory; aborting.'
|
|
63
|
+
exit 1
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Sets the data source's VCS to the VCS with the given name. Does nothing
|
|
68
|
+
# when the site's data source does not support VCSes (i.e. does not
|
|
69
|
+
# implement #vcs=).
|
|
70
|
+
#
|
|
71
|
+
# @param [String] vcs_name The name of the VCS that should be used
|
|
72
|
+
#
|
|
73
|
+
# @return [void]
|
|
74
|
+
def set_vcs(vcs_name)
|
|
75
|
+
# Skip if not possible
|
|
76
|
+
return if vcs_name.nil? || site.nil?
|
|
77
|
+
|
|
78
|
+
# Find VCS
|
|
79
|
+
vcs_class = Nanoc::Extra::VCS.named(vcs_name.to_sym)
|
|
80
|
+
if vcs_class.nil?
|
|
81
|
+
$stderr.puts "A VCS named #{vcs_name} was not found; aborting."
|
|
82
|
+
exit 1
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
site.data_sources.each do |data_source|
|
|
86
|
+
# Skip if not possible
|
|
87
|
+
next if !data_source.respond_to?(:vcs=)
|
|
88
|
+
|
|
89
|
+
# Set VCS
|
|
90
|
+
data_source.vcs = vcs_class.new
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @return [Array] The compilation stack.
|
|
95
|
+
def stack
|
|
96
|
+
(self.site && self.site.compiler.stack) || []
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @deprecated Use {Nanoc::CLI::CommandRunner} instead
|
|
102
|
+
Command = CommandRunner
|
|
103
|
+
|
|
104
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
usage 'autocompile [options]'
|
|
4
|
+
summary 'start the autocompiler'
|
|
5
|
+
aliases :aco
|
|
6
|
+
description <<-EOS
|
|
7
|
+
Start the autocompiler web server. Unless specified, the web server will run
|
|
8
|
+
on port 3000 and listen on all IP addresses. Running the autocompiler requires
|
|
9
|
+
the 'mime/types' and 'rack' gems.
|
|
10
|
+
EOS
|
|
11
|
+
|
|
12
|
+
required :H, :handler, 'specify the handler to use (webrick/mongrel/...)'
|
|
13
|
+
required :o, :host, 'specify the host to listen on (default: 0.0.0.0)'
|
|
14
|
+
required :p, :port, 'specify the port to listen on (default: 3000)'
|
|
15
|
+
|
|
16
|
+
module Nanoc::CLI::Commands
|
|
17
|
+
|
|
18
|
+
class AutoCompile < ::Nanoc::CLI::CommandRunner
|
|
19
|
+
|
|
20
|
+
def run
|
|
21
|
+
require 'rack'
|
|
22
|
+
|
|
23
|
+
# Make sure we are in a nanoc site directory
|
|
24
|
+
self.require_site
|
|
25
|
+
|
|
26
|
+
# Set options
|
|
27
|
+
options_for_rack = {
|
|
28
|
+
:Port => (options[:port] || 3000).to_i,
|
|
29
|
+
:Host => (options[:host] || '0.0.0.0')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Guess which handler we should use
|
|
33
|
+
unless handler = Rack::Handler.get(options[:handler])
|
|
34
|
+
begin
|
|
35
|
+
handler = Rack::Handler::Mongrel
|
|
36
|
+
rescue LoadError => e
|
|
37
|
+
handler = Rack::Handler::WEBrick
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Build app
|
|
42
|
+
autocompiler = Nanoc::Extra::AutoCompiler.new('.')
|
|
43
|
+
app = Rack::Builder.new do
|
|
44
|
+
use Rack::CommonLogger, $stderr
|
|
45
|
+
use Rack::ShowExceptions
|
|
46
|
+
run autocompiler
|
|
47
|
+
end.to_app
|
|
48
|
+
|
|
49
|
+
# Run autocompiler
|
|
50
|
+
puts "Running on http://#{options_for_rack[:Host]}:#{options_for_rack[:Port]}/"
|
|
51
|
+
handler.run(app, options_for_rack)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
runner Nanoc::CLI::Commands::AutoCompile
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
usage 'compile [options]'
|
|
4
|
+
summary 'compile items of this site'
|
|
5
|
+
description <<-EOS
|
|
6
|
+
Compile all items of the current site.
|
|
7
|
+
|
|
8
|
+
The compile command will show all items of the site as they are processed. The time spent compiling the item will be printed, as well as a status message, which can be one of the following:
|
|
9
|
+
|
|
10
|
+
CREATED - The compiled item did not yet exist and has been created
|
|
11
|
+
|
|
12
|
+
UPDATED - The compiled item did already exist and has been modified
|
|
13
|
+
|
|
14
|
+
IDENTICAL - The item was deemed outdated and has been recompiled, but the compiled version turned out to be identical to the already existing version
|
|
15
|
+
|
|
16
|
+
SKIP - The item was deemed not outdated and was therefore not recompiled
|
|
17
|
+
|
|
18
|
+
EOS
|
|
19
|
+
|
|
20
|
+
option :a, :all, '(ignored)'
|
|
21
|
+
option :f, :force, '(ignored)'
|
|
22
|
+
|
|
23
|
+
module Nanoc::CLI::Commands
|
|
24
|
+
|
|
25
|
+
class Compile < ::Nanoc::CLI::CommandRunner
|
|
26
|
+
|
|
27
|
+
def run
|
|
28
|
+
# Make sure we are in a nanoc site directory
|
|
29
|
+
puts "Loading site data..."
|
|
30
|
+
self.require_site
|
|
31
|
+
|
|
32
|
+
# Check presence of --all option
|
|
33
|
+
if options.has_key?(:all) || options.has_key?(:force)
|
|
34
|
+
$stderr.puts "Warning: the --force option (and its deprecated --all alias) are, as of nanoc 3.2, no longer supported and have no effect."
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Warn if trying to compile a single item
|
|
38
|
+
if arguments.size == 1
|
|
39
|
+
$stderr.puts '-' * 80
|
|
40
|
+
$stderr.puts 'Note: As of nanoc 3.2, it is no longer possible to compile a single item. When invoking the “compile” command, all items in the site will be compiled.'.make_compatible_with_env
|
|
41
|
+
$stderr.puts '-' * 80
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Give feedback
|
|
45
|
+
puts "Compiling site..."
|
|
46
|
+
|
|
47
|
+
# Initialize profiling stuff
|
|
48
|
+
time_before = Time.now
|
|
49
|
+
@rep_times = {}
|
|
50
|
+
@filter_times = {}
|
|
51
|
+
setup_notifications
|
|
52
|
+
|
|
53
|
+
# Prepare for generating diffs
|
|
54
|
+
setup_diffs
|
|
55
|
+
|
|
56
|
+
# Compile
|
|
57
|
+
self.site.compile
|
|
58
|
+
|
|
59
|
+
# Find reps
|
|
60
|
+
reps = self.site.items.map { |i| i.reps }.flatten
|
|
61
|
+
|
|
62
|
+
# Show skipped reps
|
|
63
|
+
reps.select { |r| !r.compiled? }.each do |rep|
|
|
64
|
+
rep.raw_paths.each do |snapshot_name, filename|
|
|
65
|
+
next if filename.nil?
|
|
66
|
+
duration = @rep_times[filename]
|
|
67
|
+
Nanoc::CLI::Logger.instance.file(:high, :skip, filename, duration)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Stop diffing
|
|
72
|
+
teardown_diffs
|
|
73
|
+
|
|
74
|
+
# Prune
|
|
75
|
+
if self.site.config[:auto_prune]
|
|
76
|
+
Nanoc::Extra::Pruner.new(self.site).run
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Give general feedback
|
|
80
|
+
puts
|
|
81
|
+
puts "Site compiled in #{format('%.2f', Time.now - time_before)}s."
|
|
82
|
+
|
|
83
|
+
# Give detailed feedback
|
|
84
|
+
if options.has_key?(:verbose)
|
|
85
|
+
print_profiling_feedback(reps)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def setup_notifications
|
|
90
|
+
# Diff generation
|
|
91
|
+
require 'tempfile'
|
|
92
|
+
old_contents = {}
|
|
93
|
+
Nanoc::NotificationCenter.on(:will_write_rep) do |rep, snapshot|
|
|
94
|
+
path = rep.raw_path(:snapshot => snapshot)
|
|
95
|
+
old_contents[rep] = File.file?(path) ? File.read(path) : nil
|
|
96
|
+
end
|
|
97
|
+
Nanoc::NotificationCenter.on(:rep_written) do |rep, path, is_created, is_modified|
|
|
98
|
+
if !rep.binary? && self.site.config[:enable_output_diff]
|
|
99
|
+
new_contents = File.file?(path) ? File.read(path) : nil
|
|
100
|
+
if old_contents[rep] && new_contents
|
|
101
|
+
generate_diff_for(rep, old_contents[rep], new_contents)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# File notifications
|
|
107
|
+
Nanoc::NotificationCenter.on(:rep_written) do |rep, path, is_created, is_modified|
|
|
108
|
+
action = (is_created ? :create : (is_modified ? :update : :identical))
|
|
109
|
+
duration = Time.now - @rep_times[rep.raw_path] if @rep_times[rep.raw_path]
|
|
110
|
+
Nanoc::CLI::Logger.instance.file(:high, action, path, duration)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Debug notifications
|
|
114
|
+
if self.debug?
|
|
115
|
+
Nanoc::NotificationCenter.on(:compilation_started) do |rep|
|
|
116
|
+
puts "*** Started compilation of #{rep.inspect}"
|
|
117
|
+
end
|
|
118
|
+
Nanoc::NotificationCenter.on(:compilation_ended) do |rep|
|
|
119
|
+
puts "*** Ended compilation of #{rep.inspect}"
|
|
120
|
+
puts
|
|
121
|
+
end
|
|
122
|
+
Nanoc::NotificationCenter.on(:compilation_failed) do |rep, e|
|
|
123
|
+
puts "*** Suspended compilation of #{rep.inspect}: #{e.message}"
|
|
124
|
+
end
|
|
125
|
+
Nanoc::NotificationCenter.on(:cached_content_used) do |rep|
|
|
126
|
+
puts "*** Used cached compiled content for #{rep.inspect} instead of recompiling"
|
|
127
|
+
end
|
|
128
|
+
Nanoc::NotificationCenter.on(:filtering_started) do |rep, filter_name|
|
|
129
|
+
puts "*** Started filtering #{rep.inspect} with #{filter_name}"
|
|
130
|
+
end
|
|
131
|
+
Nanoc::NotificationCenter.on(:filtering_ended) do |rep, filter_name|
|
|
132
|
+
puts "*** Ended filtering #{rep.inspect} with #{filter_name}"
|
|
133
|
+
end
|
|
134
|
+
Nanoc::NotificationCenter.on(:visit_started) do |item|
|
|
135
|
+
puts "*** Started visiting #{item.inspect}"
|
|
136
|
+
end
|
|
137
|
+
Nanoc::NotificationCenter.on(:visit_ended) do |item|
|
|
138
|
+
puts "*** Ended visiting #{item.inspect}"
|
|
139
|
+
end
|
|
140
|
+
Nanoc::NotificationCenter.on(:dependency_created) do |src, dst|
|
|
141
|
+
puts "*** Dependency created from #{src.inspect} onto #{dst.inspect}"
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Timing notifications
|
|
146
|
+
Nanoc::NotificationCenter.on(:compilation_started) do |rep|
|
|
147
|
+
@rep_times[rep.raw_path] = Time.now
|
|
148
|
+
end
|
|
149
|
+
Nanoc::NotificationCenter.on(:compilation_ended) do |rep|
|
|
150
|
+
@rep_times[rep.raw_path] = Time.now - @rep_times[rep.raw_path]
|
|
151
|
+
end
|
|
152
|
+
Nanoc::NotificationCenter.on(:filtering_started) do |rep, filter_name|
|
|
153
|
+
@filter_times[filter_name] ||= []
|
|
154
|
+
@filter_times[filter_name] << Time.now
|
|
155
|
+
start_filter_progress(rep, filter_name)
|
|
156
|
+
end
|
|
157
|
+
Nanoc::NotificationCenter.on(:filtering_ended) do |rep, filter_name|
|
|
158
|
+
@filter_times[filter_name] << Time.now - @filter_times[filter_name].pop
|
|
159
|
+
stop_filter_progress(rep, filter_name)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def setup_diffs
|
|
164
|
+
@diff_lock = Mutex.new
|
|
165
|
+
@diff_threads = []
|
|
166
|
+
FileUtils.rm('output.diff') if File.file?('output.diff')
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def teardown_diffs
|
|
170
|
+
@diff_threads.each { |t| t.join }
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def generate_diff_for(rep, old_content, new_content)
|
|
174
|
+
return if old_content == new_content
|
|
175
|
+
|
|
176
|
+
@diff_threads << Thread.new do
|
|
177
|
+
# Generate diff
|
|
178
|
+
diff = diff_strings(old_content, new_content)
|
|
179
|
+
diff.sub!(/^--- .*/, '--- ' + rep.raw_path)
|
|
180
|
+
diff.sub!(/^\+\+\+ .*/, '+++ ' + rep.raw_path)
|
|
181
|
+
|
|
182
|
+
# Write diff
|
|
183
|
+
@diff_lock.synchronize do
|
|
184
|
+
File.open('output.diff', 'a') { |io| io.write(diff) }
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# TODO move this elsewhere
|
|
190
|
+
def diff_strings(a, b)
|
|
191
|
+
require 'open3'
|
|
192
|
+
|
|
193
|
+
# Create files
|
|
194
|
+
Tempfile.open('old') do |old_file|
|
|
195
|
+
Tempfile.open('new') do |new_file|
|
|
196
|
+
# Write files
|
|
197
|
+
old_file.write(a)
|
|
198
|
+
old_file.flush
|
|
199
|
+
new_file.write(b)
|
|
200
|
+
new_file.flush
|
|
201
|
+
|
|
202
|
+
# Diff
|
|
203
|
+
cmd = [ 'diff', '-u', old_file.path, new_file.path ]
|
|
204
|
+
Open3.popen3(*cmd) do |stdin, stdout, stderr|
|
|
205
|
+
result = stdout.read
|
|
206
|
+
return (result == '' ? nil : result)
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
rescue Errno::ENOENT
|
|
211
|
+
warn 'Failed to run `diff`, so no diff with the previously compiled ' \
|
|
212
|
+
'content will be available.'
|
|
213
|
+
nil
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def start_filter_progress(rep, filter_name)
|
|
217
|
+
# Only show progress on terminals
|
|
218
|
+
return if !$stdout.tty?
|
|
219
|
+
|
|
220
|
+
@progress_thread = Thread.new do
|
|
221
|
+
delay = 1.0
|
|
222
|
+
step = 0
|
|
223
|
+
|
|
224
|
+
text = "Running #{filter_name} filter… ".make_compatible_with_env
|
|
225
|
+
|
|
226
|
+
while !Thread.current[:stopped]
|
|
227
|
+
sleep 0.1
|
|
228
|
+
|
|
229
|
+
# Wait for a while before showing text
|
|
230
|
+
delay -= 0.1
|
|
231
|
+
next if delay > 0.05
|
|
232
|
+
|
|
233
|
+
# Print progress
|
|
234
|
+
$stdout.print text + %w( | / - \\ )[step] + "\r"
|
|
235
|
+
step = (step + 1) % 4
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Clear text
|
|
239
|
+
if delay < 0.05
|
|
240
|
+
$stdout.print ' ' * (text.length + 1 + 1) + "\r"
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def stop_filter_progress(rep, filter_name)
|
|
246
|
+
# Only show progress on terminals
|
|
247
|
+
return if !$stdout.tty?
|
|
248
|
+
|
|
249
|
+
@progress_thread[:stopped] = true
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def print_profiling_feedback(reps)
|
|
253
|
+
# Get max filter length
|
|
254
|
+
max_filter_name_length = @filter_times.keys.map { |k| k.to_s.size }.max
|
|
255
|
+
return if max_filter_name_length.nil?
|
|
256
|
+
|
|
257
|
+
# Print warning if necessary
|
|
258
|
+
if reps.any? { |r| !r.compiled? }
|
|
259
|
+
$stderr.puts
|
|
260
|
+
$stderr.puts "Warning: profiling information may not be accurate because " +
|
|
261
|
+
"some items were not compiled."
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Print header
|
|
265
|
+
puts
|
|
266
|
+
puts ' ' * max_filter_name_length + ' | count min avg max tot'
|
|
267
|
+
puts '-' * max_filter_name_length + '-+-----------------------------------'
|
|
268
|
+
|
|
269
|
+
@filter_times.to_a.sort_by { |r| r[1] }.each do |row|
|
|
270
|
+
# Extract data
|
|
271
|
+
filter_name, samples = *row
|
|
272
|
+
|
|
273
|
+
# Calculate stats
|
|
274
|
+
count = samples.size
|
|
275
|
+
min = samples.min
|
|
276
|
+
tot = samples.inject { |memo, i| memo + i}
|
|
277
|
+
avg = tot/count
|
|
278
|
+
max = samples.max
|
|
279
|
+
|
|
280
|
+
# Format stats
|
|
281
|
+
count = format('%4d', count)
|
|
282
|
+
min = format('%4.2f', min)
|
|
283
|
+
avg = format('%4.2f', avg)
|
|
284
|
+
max = format('%4.2f', max)
|
|
285
|
+
tot = format('%5.2f', tot)
|
|
286
|
+
|
|
287
|
+
# Output stats
|
|
288
|
+
filter_name = format("%#{max_filter_name_length}s", filter_name)
|
|
289
|
+
puts "#{filter_name} | #{count} #{min}s #{avg}s #{max}s #{tot}s"
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
runner Nanoc::CLI::Commands::Compile
|