nanoc-cli 4.11.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/NEWS.md +3 -0
- data/README.md +3 -0
- data/lib/nanoc-cli.rb +3 -0
- data/lib/nanoc/cli.rb +237 -0
- data/lib/nanoc/cli/ansi_string_colorizer.rb +30 -0
- data/lib/nanoc/cli/cleaning_stream.rb +160 -0
- data/lib/nanoc/cli/command_runner.rb +74 -0
- data/lib/nanoc/cli/commands/compile.rb +57 -0
- data/lib/nanoc/cli/commands/create-site.rb +257 -0
- data/lib/nanoc/cli/commands/nanoc.rb +42 -0
- data/lib/nanoc/cli/commands/prune.rb +49 -0
- data/lib/nanoc/cli/commands/shell.rb +57 -0
- data/lib/nanoc/cli/commands/show-data.rb +185 -0
- data/lib/nanoc/cli/commands/show-plugins.rb +97 -0
- data/lib/nanoc/cli/commands/view.rb +68 -0
- data/lib/nanoc/cli/compile_listeners/abstract.rb +58 -0
- data/lib/nanoc/cli/compile_listeners/aggregate.rb +50 -0
- data/lib/nanoc/cli/compile_listeners/debug_printer.rb +100 -0
- data/lib/nanoc/cli/compile_listeners/diff_generator.rb +101 -0
- data/lib/nanoc/cli/compile_listeners/file_action_printer.rb +80 -0
- data/lib/nanoc/cli/compile_listeners/timing_recorder.rb +170 -0
- data/lib/nanoc/cli/error_handler.rb +365 -0
- data/lib/nanoc/cli/logger.rb +77 -0
- data/lib/nanoc/cli/stack_trace_writer.rb +51 -0
- data/lib/nanoc/cli/stream_cleaners/abstract.rb +23 -0
- data/lib/nanoc/cli/stream_cleaners/ansi_colors.rb +15 -0
- data/lib/nanoc/cli/stream_cleaners/utf8.rb +20 -0
- data/lib/nanoc/cli/transform.rb +18 -0
- data/lib/nanoc/cli/version.rb +7 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6614fdc62f969231b662ed63c693f5c2e28185ab2e139cab3fb1e88b46f4707c
|
4
|
+
data.tar.gz: 3e55bbea5197f43f0e09afcb908fc438f283a2cd5fd4a23a52ef8020a31f1d37
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0f57b9258cc0639792f33863e56785778bc6c1750b86aeab3d1131547e912799304ce8875a1bb0fa6069eab8a1bb80a2ff2377220c780d4f95a7b44f103cd71b
|
7
|
+
data.tar.gz: 6778aefc198872092095f5b9da16454a333f1f516919eb53349671339d84ad280a95e9ee460ed2505f55c6a6d84b6297d6b3fe6d5ffb903de8ae680c8d3c9083
|
data/NEWS.md
ADDED
data/README.md
ADDED
data/lib/nanoc-cli.rb
ADDED
data/lib/nanoc/cli.rb
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nanoc/core'
|
4
|
+
require 'diff/lcs'
|
5
|
+
require 'diff/lcs/hunk'
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'cri'
|
10
|
+
rescue LoadError => e
|
11
|
+
$stderr.puts e
|
12
|
+
$stderr.puts "If you are using a Gemfile, make sure that the Gemfile contains Nanoc ('gem \"nanoc\"')."
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
|
16
|
+
module Nanoc
|
17
|
+
# @api private
|
18
|
+
module CLI
|
19
|
+
# @return [Boolean] true if debug output is enabled, false if not
|
20
|
+
def self.debug?
|
21
|
+
@debug || false
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param [Boolean] boolean true if debug output should be enabled,
|
25
|
+
# false if it should not
|
26
|
+
#
|
27
|
+
# @return [void]
|
28
|
+
def self.debug=(boolean)
|
29
|
+
@debug = boolean
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.verbosity
|
33
|
+
@verbosity || 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.verbosity=(val)
|
37
|
+
@verbosity = val
|
38
|
+
end
|
39
|
+
|
40
|
+
# Wraps `$stdout` and `$stderr` in appropriate cleaning streams.
|
41
|
+
#
|
42
|
+
# @return [void]
|
43
|
+
def self.setup_cleaning_streams
|
44
|
+
$stdout = wrap_in_cleaning_stream($stdout)
|
45
|
+
$stderr = wrap_in_cleaning_stream($stderr)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Wraps the given stream in a cleaning stream. The cleaning streams will
|
49
|
+
# have the proper stream cleaners configured.
|
50
|
+
#
|
51
|
+
# @param [IO] io The stream to wrap
|
52
|
+
#
|
53
|
+
# @return [::Nanoc::CLI::CleaningStream]
|
54
|
+
def self.wrap_in_cleaning_stream(io)
|
55
|
+
cio = ::Nanoc::CLI::CleaningStream.new(io)
|
56
|
+
|
57
|
+
unless enable_utf8?(io)
|
58
|
+
cio.add_stream_cleaner(Nanoc::CLI::StreamCleaners::UTF8)
|
59
|
+
end
|
60
|
+
|
61
|
+
unless enable_ansi_colors?(io)
|
62
|
+
cio.add_stream_cleaner(Nanoc::CLI::StreamCleaners::ANSIColors)
|
63
|
+
end
|
64
|
+
|
65
|
+
cio
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Boolean] true if UTF-8 support is present, false if not
|
69
|
+
def self.enable_utf8?(io)
|
70
|
+
return true unless io.tty?
|
71
|
+
|
72
|
+
%w[LC_ALL LC_CTYPE LANG].any? { |e| ENV[e] =~ /UTF/i }
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [Boolean] true if color support is present, false if not
|
76
|
+
def self.enable_ansi_colors?(io)
|
77
|
+
io.tty? && !ENV.key?('NO_COLOR')
|
78
|
+
end
|
79
|
+
|
80
|
+
# Invokes the Nanoc command-line tool with the given arguments.
|
81
|
+
#
|
82
|
+
# @param [Array<String>] args An array of command-line arguments
|
83
|
+
#
|
84
|
+
# @return [void]
|
85
|
+
def self.run(args)
|
86
|
+
Nanoc::CLI::ErrorHandler.handle_while do
|
87
|
+
setup
|
88
|
+
root_command.run(args)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [Cri::Command] The root command, i.e. the command-line tool itself
|
93
|
+
def self.root_command
|
94
|
+
@root_command
|
95
|
+
end
|
96
|
+
|
97
|
+
# Adds the given command to the collection of available commands.
|
98
|
+
#
|
99
|
+
# @param [Cri::Command] cmd The command to add
|
100
|
+
#
|
101
|
+
# @return [void]
|
102
|
+
def self.add_command(cmd)
|
103
|
+
root_command.add_command(cmd)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Schedules the given block to be executed after the CLI has been set up.
|
107
|
+
#
|
108
|
+
# @return [void]
|
109
|
+
def self.after_setup(&block)
|
110
|
+
# TODO: decide what should happen if the CLI is already set up
|
111
|
+
add_after_setup_proc(block)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Makes the command-line interface ready for use.
|
115
|
+
#
|
116
|
+
# @return [void]
|
117
|
+
def self.setup
|
118
|
+
Nanoc::CLI.setup_cleaning_streams
|
119
|
+
setup_commands
|
120
|
+
load_custom_commands
|
121
|
+
after_setup_procs.each(&:call)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Sets up the root command and base subcommands.
|
125
|
+
#
|
126
|
+
# @return [void]
|
127
|
+
def self.setup_commands
|
128
|
+
# Reinit
|
129
|
+
@root_command = nil
|
130
|
+
|
131
|
+
# Add root command
|
132
|
+
filename = __dir__ + '/cli/commands/nanoc.rb'
|
133
|
+
@root_command = Cri::Command.load_file(filename, infer_name: true)
|
134
|
+
|
135
|
+
# Add help command
|
136
|
+
help_cmd = Cri::Command.new_basic_help
|
137
|
+
add_command(help_cmd)
|
138
|
+
|
139
|
+
# Add other commands
|
140
|
+
cmd_filenames = Dir[__dir__ + '/cli/commands/*.rb']
|
141
|
+
cmd_filenames.each do |cmd_filename|
|
142
|
+
basename = File.basename(cmd_filename, '.rb')
|
143
|
+
|
144
|
+
next if basename == 'nanoc'
|
145
|
+
|
146
|
+
cmd = Cri::Command.load_file(cmd_filename, infer_name: true)
|
147
|
+
add_command(cmd)
|
148
|
+
end
|
149
|
+
|
150
|
+
if defined?(Bundler)
|
151
|
+
# Discover external commands through Bundler
|
152
|
+
begin
|
153
|
+
Bundler.require(:nanoc)
|
154
|
+
rescue Bundler::GemfileNotFound
|
155
|
+
# When running Nanoc with Bundler being defined but
|
156
|
+
# no gemfile being present (rubygems automatically loads
|
157
|
+
# Bundler when executing from command line), don't crash.
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Loads site-specific commands.
|
163
|
+
#
|
164
|
+
# @return [void]
|
165
|
+
def self.load_custom_commands
|
166
|
+
if Nanoc::Core::SiteLoader.cwd_is_nanoc_site?
|
167
|
+
config = Nanoc::Core::ConfigLoader.new.new_from_cwd
|
168
|
+
config[:commands_dirs].each do |path|
|
169
|
+
load_commands_at(path)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.load_commands_at(path)
|
175
|
+
recursive_contents_of(path).each do |filename|
|
176
|
+
# Create command
|
177
|
+
command = Cri::Command.load_file(filename, infer_name: true)
|
178
|
+
|
179
|
+
# Get supercommand
|
180
|
+
pieces = filename.gsub(/^#{path}\/|\.rb$/, '').split('/')
|
181
|
+
pieces = pieces[0, pieces.size - 1] || []
|
182
|
+
root = Nanoc::CLI.root_command
|
183
|
+
supercommand = pieces.reduce(root) do |cmd, piece|
|
184
|
+
cmd.nil? ? nil : cmd.command_named(piece)
|
185
|
+
end
|
186
|
+
|
187
|
+
# Add to supercommand
|
188
|
+
if supercommand.nil?
|
189
|
+
raise "Cannot load command at #{filename} because its supercommand cannot be found"
|
190
|
+
end
|
191
|
+
|
192
|
+
supercommand.add_command(command)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# @return [Array] The directory contents
|
197
|
+
def self.recursive_contents_of(path)
|
198
|
+
return [] unless File.directory?(path)
|
199
|
+
|
200
|
+
files, dirs = *Dir[path + '/*'].sort.partition { |e| File.file?(e) }
|
201
|
+
dirs.each { |d| files.concat recursive_contents_of(d) }
|
202
|
+
files
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.after_setup_procs
|
206
|
+
@after_setup_procs || []
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.add_after_setup_proc(proc)
|
210
|
+
@after_setup_procs ||= []
|
211
|
+
@after_setup_procs << proc
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
inflector_class = Class.new(Zeitwerk::Inflector) do
|
217
|
+
def camelize(basename, abspath)
|
218
|
+
case basename
|
219
|
+
when 'version', 'cli', 'utf8'
|
220
|
+
basename.upcase
|
221
|
+
when 'ansi_colors'
|
222
|
+
'ANSIColors'
|
223
|
+
when 'ansi_string_colorizer'
|
224
|
+
'ANSIStringColorizer'
|
225
|
+
else
|
226
|
+
super
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
loader = Zeitwerk::Loader.new
|
232
|
+
loader.inflector = inflector_class.new
|
233
|
+
loader.push_dir(__dir__ + '/..')
|
234
|
+
loader.ignore(__dir__ + '/../nanoc-cli.rb')
|
235
|
+
loader.ignore(__dir__ + '/cli/commands')
|
236
|
+
loader.setup
|
237
|
+
loader.eager_load
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module CLI
|
5
|
+
# A simple ANSI colorizer for strings. When given a string and a list of
|
6
|
+
# attributes, it returns a colorized string.
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
module ANSIStringColorizer
|
10
|
+
# TODO: complete mapping
|
11
|
+
MAPPING = {
|
12
|
+
bold: "\e[1m",
|
13
|
+
red: "\e[31m",
|
14
|
+
green: "\e[32m",
|
15
|
+
yellow: "\e[33m",
|
16
|
+
blue: "\e[34m",
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
# @param [String] str The string to colorize
|
20
|
+
#
|
21
|
+
# @param [Array] attrs An array of attributes from `MAPPING` to colorize the
|
22
|
+
# string with
|
23
|
+
#
|
24
|
+
# @return [String] A string colorized using the given attributes
|
25
|
+
def self.c(str, *attrs)
|
26
|
+
attrs.map { |a| MAPPING[a] }.join('') + str + "\e[0m"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module CLI
|
5
|
+
# An output stream that passes output through stream cleaners. This can be
|
6
|
+
# used to strip ANSI color sequences, for instance.
|
7
|
+
class CleaningStream
|
8
|
+
# @param [IO, StringIO] stream The stream to wrap
|
9
|
+
def initialize(stream)
|
10
|
+
@stream = stream
|
11
|
+
@stream_cleaners = []
|
12
|
+
end
|
13
|
+
|
14
|
+
# Adds a stream cleaner for the given class to this cleaning stream. If the
|
15
|
+
# cleaning stream already has the given stream cleaner, nothing happens.
|
16
|
+
#
|
17
|
+
# @param [Nanoc::CLI::StreamCleaners::Abstract] klass The class of the
|
18
|
+
# stream cleaner to add
|
19
|
+
#
|
20
|
+
# @return [void]
|
21
|
+
def add_stream_cleaner(klass)
|
22
|
+
unless @stream_cleaners.map(&:class).include?(klass)
|
23
|
+
@stream_cleaners << klass.new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Removes the stream cleaner for the given class from this cleaning stream.
|
28
|
+
# If the cleaning stream does not have the given stream cleaner, nothing
|
29
|
+
# happens.
|
30
|
+
#
|
31
|
+
# @param [Nanoc::CLI::StreamCleaners::Abstract] klass The class of the
|
32
|
+
# stream cleaner to add
|
33
|
+
#
|
34
|
+
# @return [void]
|
35
|
+
def remove_stream_cleaner(klass)
|
36
|
+
@stream_cleaners.delete_if { |c| c.class == klass }
|
37
|
+
end
|
38
|
+
|
39
|
+
# @group IO proxy methods
|
40
|
+
|
41
|
+
# @see IO#write
|
42
|
+
def write(str)
|
43
|
+
_nanoc_swallow_broken_pipe_errors_while do
|
44
|
+
@stream.write(_nanoc_clean(str))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @see IO#<<
|
49
|
+
def <<(str)
|
50
|
+
_nanoc_swallow_broken_pipe_errors_while do
|
51
|
+
@stream.<<(_nanoc_clean(str))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @see IO#tty?
|
56
|
+
def tty?
|
57
|
+
@cached_is_tty ||= @stream.tty?
|
58
|
+
end
|
59
|
+
|
60
|
+
# @see IO#isatty
|
61
|
+
def isatty
|
62
|
+
tty?
|
63
|
+
end
|
64
|
+
|
65
|
+
# @see IO#flush
|
66
|
+
def flush
|
67
|
+
_nanoc_swallow_broken_pipe_errors_while do
|
68
|
+
@stream.flush
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# @see IO#tell
|
73
|
+
def tell
|
74
|
+
@stream.tell
|
75
|
+
end
|
76
|
+
|
77
|
+
# @see IO#print
|
78
|
+
def print(str)
|
79
|
+
_nanoc_swallow_broken_pipe_errors_while do
|
80
|
+
@stream.print(_nanoc_clean(str))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# @see IO#puts
|
85
|
+
def puts(*str)
|
86
|
+
_nanoc_swallow_broken_pipe_errors_while do
|
87
|
+
@stream.puts(*str.map { |ss| _nanoc_clean(ss) })
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# @see StringIO#string
|
92
|
+
def string
|
93
|
+
@stream.string
|
94
|
+
end
|
95
|
+
|
96
|
+
# @see IO#reopen
|
97
|
+
def reopen(*args)
|
98
|
+
@stream.reopen(*args)
|
99
|
+
end
|
100
|
+
|
101
|
+
# @see IO#close
|
102
|
+
def close
|
103
|
+
@stream.close
|
104
|
+
end
|
105
|
+
|
106
|
+
# @see File#exist?
|
107
|
+
def exist?
|
108
|
+
@stream.exist?
|
109
|
+
end
|
110
|
+
|
111
|
+
# @see File.exists?
|
112
|
+
def exists?
|
113
|
+
@stream.exists?
|
114
|
+
end
|
115
|
+
|
116
|
+
# @see IO.winsize
|
117
|
+
def winsize
|
118
|
+
@stream.winsize
|
119
|
+
end
|
120
|
+
|
121
|
+
# @see IO.winsize=
|
122
|
+
def winsize=(arg)
|
123
|
+
@stream.winsize = arg
|
124
|
+
end
|
125
|
+
|
126
|
+
# @see IO.sync
|
127
|
+
def sync
|
128
|
+
@stream.sync
|
129
|
+
end
|
130
|
+
|
131
|
+
# @see IO.sync=
|
132
|
+
def sync=(arg)
|
133
|
+
@stream.sync = arg
|
134
|
+
end
|
135
|
+
|
136
|
+
# @see IO.sync=
|
137
|
+
def external_encoding
|
138
|
+
@stream.external_encoding
|
139
|
+
end
|
140
|
+
|
141
|
+
# @see ARGF.set_encoding
|
142
|
+
# rubocop:disable Naming/AccessorMethodName
|
143
|
+
def set_encoding(*args)
|
144
|
+
@stream.set_encoding(*args)
|
145
|
+
end
|
146
|
+
# rubocop:enable Naming/AccessorMethodName
|
147
|
+
|
148
|
+
protected
|
149
|
+
|
150
|
+
def _nanoc_clean(str)
|
151
|
+
@stream_cleaners.reduce(str.to_s.scrub) { |acc, elem| elem.clean(acc) }
|
152
|
+
end
|
153
|
+
|
154
|
+
def _nanoc_swallow_broken_pipe_errors_while
|
155
|
+
yield
|
156
|
+
rescue Errno::EPIPE
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|