toys-core 0.3.6 → 0.3.7
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/lib/toys-core.rb +20 -5
- data/lib/toys/cli.rb +39 -32
- data/lib/toys/core_version.rb +1 -1
- data/lib/toys/{tool → definition}/acceptor.rb +21 -15
- data/lib/toys/{utils/line_output.rb → definition/alias.rb} +47 -59
- data/lib/toys/{tool/arg_definition.rb → definition/arg.rb} +17 -7
- data/lib/toys/{tool/flag_definition.rb → definition/flag.rb} +19 -9
- data/lib/toys/definition/tool.rb +574 -0
- data/lib/toys/dsl/arg.rb +118 -0
- data/lib/toys/dsl/flag.rb +132 -0
- data/lib/toys/dsl/tool.rb +521 -0
- data/lib/toys/errors.rb +2 -2
- data/lib/toys/helpers.rb +3 -3
- data/lib/toys/helpers/exec.rb +31 -25
- data/lib/toys/helpers/fileutils.rb +8 -2
- data/lib/toys/helpers/highline.rb +8 -1
- data/lib/toys/{alias.rb → helpers/terminal.rb} +44 -53
- data/lib/toys/input_file.rb +61 -0
- data/lib/toys/loader.rb +87 -77
- data/lib/toys/middleware.rb +3 -3
- data/lib/toys/middleware/add_verbosity_flags.rb +22 -20
- data/lib/toys/middleware/base.rb +53 -5
- data/lib/toys/middleware/handle_usage_errors.rb +9 -12
- data/lib/toys/middleware/set_default_descriptions.rb +6 -7
- data/lib/toys/middleware/show_help.rb +71 -67
- data/lib/toys/middleware/show_root_version.rb +9 -9
- data/lib/toys/runner.rb +157 -0
- data/lib/toys/template.rb +4 -3
- data/lib/toys/templates.rb +2 -2
- data/lib/toys/templates/clean.rb +2 -2
- data/lib/toys/templates/gem_build.rb +5 -5
- data/lib/toys/templates/minitest.rb +2 -2
- data/lib/toys/templates/rubocop.rb +2 -2
- data/lib/toys/templates/yardoc.rb +2 -2
- data/lib/toys/tool.rb +168 -625
- data/lib/toys/utils/exec.rb +19 -18
- data/lib/toys/utils/gems.rb +140 -0
- data/lib/toys/utils/help_text.rb +25 -20
- data/lib/toys/utils/terminal.rb +412 -0
- data/lib/toys/utils/wrappable_string.rb +3 -1
- metadata +15 -24
- data/lib/toys/config_dsl.rb +0 -699
- data/lib/toys/context.rb +0 -290
- data/lib/toys/helpers/spinner.rb +0 -142
data/lib/toys/context.rb
DELETED
@@ -1,290 +0,0 @@
|
|
1
|
-
# Copyright 2018 Daniel Azuma
|
2
|
-
#
|
3
|
-
# All rights reserved.
|
4
|
-
#
|
5
|
-
# Redistribution and use in source and binary forms, with or without
|
6
|
-
# modification, are permitted provided that the following conditions are met:
|
7
|
-
#
|
8
|
-
# * Redistributions of source code must retain the above copyright notice,
|
9
|
-
# this list of conditions and the following disclaimer.
|
10
|
-
# * Redistributions in binary form must reproduce the above copyright notice,
|
11
|
-
# this list of conditions and the following disclaimer in the documentation
|
12
|
-
# and/or other materials provided with the distribution.
|
13
|
-
# * Neither the name of the copyright holder, nor the names of any other
|
14
|
-
# contributors to this software, may be used to endorse or promote products
|
15
|
-
# derived from this software without specific prior written permission.
|
16
|
-
#
|
17
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
21
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
22
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
23
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
24
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
25
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
26
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
28
|
-
;
|
29
|
-
|
30
|
-
require "logger"
|
31
|
-
|
32
|
-
module Toys
|
33
|
-
##
|
34
|
-
# This class manages the object context in effect during the execution of a
|
35
|
-
# tool. The context is a hash of key-value pairs.
|
36
|
-
#
|
37
|
-
# Flags and arguments defined by your tool normally report their values in
|
38
|
-
# the context, using keys that are strings or symbols.
|
39
|
-
#
|
40
|
-
# Keys that are neither strings nor symbols are by convention used for other
|
41
|
-
# context information, including:
|
42
|
-
# * Common information such as the {Toys::Tool} object being executed, the
|
43
|
-
# arguments originally passed to it, or the usage error string. These
|
44
|
-
# well-known keys can be accessed via constants in the {Toys::Context}
|
45
|
-
# module.
|
46
|
-
# * Common settings such as the verbosity level, and whether to exit
|
47
|
-
# immediately if a subprocess exits with a nonzero result. These keys are
|
48
|
-
# also present as {Toys::Context} constants.
|
49
|
-
# * Private information used internally by middleware and helpers.
|
50
|
-
#
|
51
|
-
# This class provides convenience accessors for common keys and settings, and
|
52
|
-
# you can retrieve argument-set keys using the {#options} hash.
|
53
|
-
#
|
54
|
-
class Context
|
55
|
-
##
|
56
|
-
# Context key for the currently running CLI.
|
57
|
-
# @return [Object]
|
58
|
-
#
|
59
|
-
CLI = ::Object.new.freeze
|
60
|
-
|
61
|
-
##
|
62
|
-
# Context key for the verbosity value. Verbosity is an integer defaulting
|
63
|
-
# to 0, with higher values meaning more verbose and lower meaning quieter.
|
64
|
-
# @return [Object]
|
65
|
-
#
|
66
|
-
VERBOSITY = ::Object.new.freeze
|
67
|
-
|
68
|
-
##
|
69
|
-
# Context key for the `Toys::Tool` object being executed.
|
70
|
-
# @return [Object]
|
71
|
-
#
|
72
|
-
TOOL = ::Object.new.freeze
|
73
|
-
|
74
|
-
##
|
75
|
-
# Context key for the full name of the tool being executed. Value is an
|
76
|
-
# array of strings.
|
77
|
-
# @return [Object]
|
78
|
-
#
|
79
|
-
TOOL_NAME = ::Object.new.freeze
|
80
|
-
|
81
|
-
##
|
82
|
-
# Context key for the active `Toys::Loader` object.
|
83
|
-
# @return [Object]
|
84
|
-
#
|
85
|
-
LOADER = ::Object.new.freeze
|
86
|
-
|
87
|
-
##
|
88
|
-
# Context key for the active `Logger` object.
|
89
|
-
# @return [Object]
|
90
|
-
#
|
91
|
-
LOGGER = ::Object.new.freeze
|
92
|
-
|
93
|
-
##
|
94
|
-
# Context key for the name of the toys binary. Value is a string.
|
95
|
-
# @return [Object]
|
96
|
-
#
|
97
|
-
BINARY_NAME = ::Object.new.freeze
|
98
|
-
|
99
|
-
##
|
100
|
-
# Context key for the argument list passed to the current tool. Value is
|
101
|
-
# an array of strings.
|
102
|
-
# @return [Object]
|
103
|
-
#
|
104
|
-
ARGS = ::Object.new.freeze
|
105
|
-
|
106
|
-
##
|
107
|
-
# Context key for the usage error raised. Value is a string if there was
|
108
|
-
# an error, or nil if there was no error.
|
109
|
-
# @return [Object]
|
110
|
-
#
|
111
|
-
USAGE_ERROR = ::Object.new.freeze
|
112
|
-
|
113
|
-
##
|
114
|
-
# Context key for whether nonzero exit codes from subprocesses should cause
|
115
|
-
# an immediate exit. Value is a truthy or falsy value.
|
116
|
-
# @return [Object]
|
117
|
-
#
|
118
|
-
EXIT_ON_NONZERO_STATUS = ::Object.new.freeze
|
119
|
-
|
120
|
-
##
|
121
|
-
# Create a Context object. Applications generally will not need to create
|
122
|
-
# these objects directly; they are created by the tool when it is preparing
|
123
|
-
# for execution.
|
124
|
-
# @private
|
125
|
-
#
|
126
|
-
# @param [Toys::CLI] cli
|
127
|
-
# @param [Hash] data
|
128
|
-
#
|
129
|
-
def initialize(cli, data)
|
130
|
-
@_data = data
|
131
|
-
@_data[CLI] = cli
|
132
|
-
@_data[LOADER] = cli.loader
|
133
|
-
@_data[BINARY_NAME] = cli.binary_name
|
134
|
-
@_data[LOGGER] = cli.logger
|
135
|
-
end
|
136
|
-
|
137
|
-
##
|
138
|
-
# Return the currently running CLI.
|
139
|
-
# @return [Toys::CLI]
|
140
|
-
#
|
141
|
-
def cli
|
142
|
-
@_data[CLI]
|
143
|
-
end
|
144
|
-
|
145
|
-
##
|
146
|
-
# Return the current verbosity setting as an integer.
|
147
|
-
# @return [Integer]
|
148
|
-
#
|
149
|
-
def verbosity
|
150
|
-
@_data[VERBOSITY]
|
151
|
-
end
|
152
|
-
|
153
|
-
##
|
154
|
-
# Return the tool being executed.
|
155
|
-
# @return [Toys::Tool]
|
156
|
-
#
|
157
|
-
def tool
|
158
|
-
@_data[TOOL]
|
159
|
-
end
|
160
|
-
|
161
|
-
##
|
162
|
-
# Return the name of the tool being executed, as an array of strings.
|
163
|
-
# @return [Array[String]]
|
164
|
-
#
|
165
|
-
def tool_name
|
166
|
-
@_data[TOOL_NAME]
|
167
|
-
end
|
168
|
-
|
169
|
-
##
|
170
|
-
# Return the raw arguments passed to the tool, as an array of strings.
|
171
|
-
# This does not include the tool name itself.
|
172
|
-
# @return [Array[String]]
|
173
|
-
#
|
174
|
-
def args
|
175
|
-
@_data[ARGS]
|
176
|
-
end
|
177
|
-
|
178
|
-
##
|
179
|
-
# Return any usage error detected during argument parsing, or `nil` if
|
180
|
-
# no error was detected.
|
181
|
-
# @return [String,nil]
|
182
|
-
#
|
183
|
-
def usage_error
|
184
|
-
@_data[USAGE_ERROR]
|
185
|
-
end
|
186
|
-
|
187
|
-
##
|
188
|
-
# Return the logger for this execution.
|
189
|
-
# @return [Logger]
|
190
|
-
#
|
191
|
-
def logger
|
192
|
-
@_data[LOGGER]
|
193
|
-
end
|
194
|
-
|
195
|
-
##
|
196
|
-
# Return the active loader that can be used to get other tools.
|
197
|
-
# @return [Toys::Loader]
|
198
|
-
#
|
199
|
-
def loader
|
200
|
-
@_data[LOADER]
|
201
|
-
end
|
202
|
-
|
203
|
-
##
|
204
|
-
# Return the name of the binary that was executed.
|
205
|
-
# @return [String]
|
206
|
-
#
|
207
|
-
def binary_name
|
208
|
-
@_data[BINARY_NAME]
|
209
|
-
end
|
210
|
-
|
211
|
-
##
|
212
|
-
# Return an option or other piece of data by key.
|
213
|
-
#
|
214
|
-
# @param [Symbol] key
|
215
|
-
# @return [Object]
|
216
|
-
#
|
217
|
-
def [](key)
|
218
|
-
@_data[key]
|
219
|
-
end
|
220
|
-
alias get []
|
221
|
-
|
222
|
-
##
|
223
|
-
# Set an option or other piece of context data by key.
|
224
|
-
#
|
225
|
-
# @param [Symbol] key
|
226
|
-
# @param [Object] value
|
227
|
-
#
|
228
|
-
def []=(key, value)
|
229
|
-
@_data[key] = value
|
230
|
-
end
|
231
|
-
|
232
|
-
##
|
233
|
-
# Set an option or other piece of context data by key.
|
234
|
-
#
|
235
|
-
# @param [Symbol] key
|
236
|
-
# @param [Object] value
|
237
|
-
#
|
238
|
-
def set(key, value = nil)
|
239
|
-
if key.is_a?(::Hash)
|
240
|
-
@_data.merge!(key)
|
241
|
-
else
|
242
|
-
@_data[key] = value
|
243
|
-
end
|
244
|
-
self
|
245
|
-
end
|
246
|
-
|
247
|
-
##
|
248
|
-
# Returns the subset of the context that uses string or symbol keys. By
|
249
|
-
# convention, this includes keys that are set by tool flags and arguments,
|
250
|
-
# but does not include well-known context values such as verbosity or
|
251
|
-
# private context values used by middleware or helpers.
|
252
|
-
#
|
253
|
-
# @return [Hash]
|
254
|
-
#
|
255
|
-
def options
|
256
|
-
@_data.select do |k, _v|
|
257
|
-
k.is_a?(::Symbol) || k.is_a?(::String)
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
##
|
262
|
-
# Execute another tool, given by the provided arguments.
|
263
|
-
#
|
264
|
-
# @param [String...] args The name of the tool to run along with its
|
265
|
-
# command line arguments and flags.
|
266
|
-
# @param [Toys::CLI,nil] cli The CLI to use to execute the tool. If `nil`
|
267
|
-
# (the default), uses the current CLI.
|
268
|
-
# @param [Boolean] exit_on_nonzero_status If true, exit immediately if the
|
269
|
-
# run returns a nonzero error code.
|
270
|
-
# @return [Integer] The resulting status code
|
271
|
-
#
|
272
|
-
def run(*args, cli: nil, exit_on_nonzero_status: nil)
|
273
|
-
cli ||= @_data[CLI]
|
274
|
-
exit_on_nonzero_status = @_data[EXIT_ON_NONZERO_STATUS] if exit_on_nonzero_status.nil?
|
275
|
-
code = cli.run(args.flatten, verbosity: @_data[VERBOSITY])
|
276
|
-
exit(code) if exit_on_nonzero_status && !code.zero?
|
277
|
-
code
|
278
|
-
end
|
279
|
-
|
280
|
-
##
|
281
|
-
# Exit immediately with the given status code
|
282
|
-
#
|
283
|
-
# @param [Integer] code The status code, which should be 0 for no error,
|
284
|
-
# or nonzero for an error condition.
|
285
|
-
#
|
286
|
-
def exit(code)
|
287
|
-
throw :result, code
|
288
|
-
end
|
289
|
-
end
|
290
|
-
end
|
data/lib/toys/helpers/spinner.rb
DELETED
@@ -1,142 +0,0 @@
|
|
1
|
-
# Copyright 2018 Daniel Azuma
|
2
|
-
#
|
3
|
-
# All rights reserved.
|
4
|
-
#
|
5
|
-
# Redistribution and use in source and binary forms, with or without
|
6
|
-
# modification, are permitted provided that the following conditions are met:
|
7
|
-
#
|
8
|
-
# * Redistributions of source code must retain the above copyright notice,
|
9
|
-
# this list of conditions and the following disclaimer.
|
10
|
-
# * Redistributions in binary form must reproduce the above copyright notice,
|
11
|
-
# this list of conditions and the following disclaimer in the documentation
|
12
|
-
# and/or other materials provided with the distribution.
|
13
|
-
# * Neither the name of the copyright holder, nor the names of any other
|
14
|
-
# contributors to this software, may be used to endorse or promote products
|
15
|
-
# derived from this software without specific prior written permission.
|
16
|
-
#
|
17
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
21
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
22
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
23
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
24
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
25
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
26
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
28
|
-
;
|
29
|
-
|
30
|
-
require "monitor"
|
31
|
-
require "highline"
|
32
|
-
|
33
|
-
module Toys
|
34
|
-
module Helpers
|
35
|
-
##
|
36
|
-
# A module that provides a spinner output.
|
37
|
-
#
|
38
|
-
module Spinner
|
39
|
-
##
|
40
|
-
# Default length of a single frame, in seconds.
|
41
|
-
# @return [Float]
|
42
|
-
#
|
43
|
-
DEFAULT_FRAME_LENGTH = 0.1
|
44
|
-
|
45
|
-
##
|
46
|
-
# Default set of frames.
|
47
|
-
# @return [Array<String,Array(String,Integer)>]
|
48
|
-
#
|
49
|
-
DEFAULT_FRAMES = ["-", "\\", "|", "/"].freeze
|
50
|
-
|
51
|
-
##
|
52
|
-
# Display a spinner during a task. You should provide a block that
|
53
|
-
# performs the long-running task. While the block is executing, a
|
54
|
-
# spinner will be displayed.
|
55
|
-
#
|
56
|
-
# @param [String] leading_text Optional leading string to display to the
|
57
|
-
# left of the spinner. Default is the empty string.
|
58
|
-
# @param [Float] frame_length Length of a single frame, in seconds.
|
59
|
-
# Defaults to {DEFAULT_FRAME_LENGTH}.
|
60
|
-
# @param [Array<String>] frames An array of frames. Defaults to
|
61
|
-
# {DEFAULT_FRAMES}.
|
62
|
-
# @param [Symbol,Array<Symbol>] style A HighLine style or array of styles
|
63
|
-
# to apply to all frames in the spinner. Defaults to empty,
|
64
|
-
# @param [IO] stream Stream to output the spinner to. Defaults to STDOUT.
|
65
|
-
# Note the spinner will be disabled if this stream is not a tty.
|
66
|
-
# @param [String] final_text Optional final string to display when the
|
67
|
-
# spinner is complete. Default is the empty string. A common practice
|
68
|
-
# is to set this to newline.
|
69
|
-
#
|
70
|
-
def spinner(leading_text: "",
|
71
|
-
frame_length: DEFAULT_FRAME_LENGTH,
|
72
|
-
frames: DEFAULT_FRAMES,
|
73
|
-
style: nil,
|
74
|
-
stream: $stdout,
|
75
|
-
final_text: "")
|
76
|
-
return nil unless block_given?
|
77
|
-
unless leading_text.empty?
|
78
|
-
stream.write(leading_text)
|
79
|
-
stream.flush
|
80
|
-
end
|
81
|
-
spin = SpinDriver.new(stream, frames, Array(style), frame_length)
|
82
|
-
begin
|
83
|
-
yield
|
84
|
-
ensure
|
85
|
-
spin.stop
|
86
|
-
unless final_text.empty?
|
87
|
-
stream.write(final_text)
|
88
|
-
stream.flush
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
## @private
|
94
|
-
class SpinDriver
|
95
|
-
include ::MonitorMixin
|
96
|
-
|
97
|
-
def initialize(stream, frames, style, frame_length)
|
98
|
-
@stream = stream
|
99
|
-
@frames = frames.map do |f|
|
100
|
-
[
|
101
|
-
style.empty? ? f : ::HighLine.color(f, *style),
|
102
|
-
::HighLine.uncolor(f).size
|
103
|
-
]
|
104
|
-
end
|
105
|
-
@frame_length = frame_length
|
106
|
-
@cur_frame = 0
|
107
|
-
@stopping = false
|
108
|
-
@cond = new_cond
|
109
|
-
super()
|
110
|
-
@thread = @stream.tty? ? start_thread : nil
|
111
|
-
end
|
112
|
-
|
113
|
-
def stop
|
114
|
-
synchronize do
|
115
|
-
@stopping = true
|
116
|
-
@cond.broadcast
|
117
|
-
end
|
118
|
-
@thread.join if @thread
|
119
|
-
self
|
120
|
-
end
|
121
|
-
|
122
|
-
private
|
123
|
-
|
124
|
-
def start_thread
|
125
|
-
::Thread.new do
|
126
|
-
synchronize do
|
127
|
-
until @stopping
|
128
|
-
@stream.write(@frames[@cur_frame][0])
|
129
|
-
@stream.flush
|
130
|
-
@cond.wait(@frame_length)
|
131
|
-
size = @frames[@cur_frame][1]
|
132
|
-
@stream.write("\b" * size + " " * size + "\b" * size)
|
133
|
-
@cur_frame += 1
|
134
|
-
@cur_frame = 0 if @cur_frame >= @frames.size
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|