planter-cli 0.0.4 → 3.0.2
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/.gitignore +3 -0
- data/.gitmodules +3 -0
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +31 -0
- data/README.md +33 -4
- data/Rakefile +52 -16
- data/bin/plant +2 -2
- data/docker/Dockerfile +2 -4
- data/docker/Dockerfile-2.6 +4 -6
- data/docker/Dockerfile-2.7 +4 -6
- data/docker/Dockerfile-3.0 +4 -5
- data/docker/Dockerfile-3.3 +11 -0
- data/docker/sources.list +11 -0
- data/lib/planter/array.rb +17 -0
- data/lib/planter/fileentry.rb +5 -1
- data/lib/planter/filelist.rb +13 -4
- data/lib/planter/hash.rb +17 -1
- data/lib/planter/plant.rb +5 -3
- data/lib/planter/prompt.rb +5 -5
- data/lib/planter/string.rb +22 -0
- data/lib/planter/tag.rb +91 -0
- data/lib/planter/version.rb +1 -1
- data/lib/planter.rb +34 -18
- data/lib/tty-spinner/.editorconfig +9 -0
- data/lib/tty-spinner/.github/FUNDING.yml +1 -0
- data/lib/tty-spinner/.github/ISSUE_TEMPLATE/BUG_REPORT.md +31 -0
- data/lib/tty-spinner/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md +23 -0
- data/lib/tty-spinner/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/lib/tty-spinner/.github/PULL_REQUEST_TEMPLATE.md +19 -0
- data/lib/tty-spinner/.github/workflows/ci.yml +59 -0
- data/lib/tty-spinner/.gitignore +14 -0
- data/lib/tty-spinner/.rspec +2 -0
- data/lib/tty-spinner/.rubocop.yml +78 -0
- data/lib/tty-spinner/CHANGELOG.md +151 -0
- data/lib/tty-spinner/CODE_OF_CONDUCT.md +132 -0
- data/lib/tty-spinner/Gemfile +17 -0
- data/lib/tty-spinner/LICENSE.txt +22 -0
- data/lib/tty-spinner/README.md +581 -0
- data/lib/tty-spinner/Rakefile +10 -0
- data/lib/tty-spinner/appveyor.yml +33 -0
- data/lib/tty-spinner/bin/console +14 -0
- data/lib/tty-spinner/bin/setup +8 -0
- data/lib/tty-spinner/demo.gif +0 -0
- data/lib/tty-spinner/examples/auto_spin.rb +10 -0
- data/lib/tty-spinner/examples/basic.rb +10 -0
- data/lib/tty-spinner/examples/clear.rb +11 -0
- data/lib/tty-spinner/examples/color.rb +14 -0
- data/lib/tty-spinner/examples/error.rb +11 -0
- data/lib/tty-spinner/examples/formats.rb +13 -0
- data/lib/tty-spinner/examples/hide_cursor.rb +14 -0
- data/lib/tty-spinner/examples/log.rb +13 -0
- data/lib/tty-spinner/examples/multi/basic.rb +15 -0
- data/lib/tty-spinner/examples/multi/basic_top_level.rb +15 -0
- data/lib/tty-spinner/examples/multi/custom_style.rb +28 -0
- data/lib/tty-spinner/examples/multi/files.rb +16 -0
- data/lib/tty-spinner/examples/multi/jobs.rb +11 -0
- data/lib/tty-spinner/examples/multi/multi.rb +19 -0
- data/lib/tty-spinner/examples/multi/multi_top_level.rb +20 -0
- data/lib/tty-spinner/examples/multi/pause.rb +28 -0
- data/lib/tty-spinner/examples/multi/threaded.rb +30 -0
- data/lib/tty-spinner/examples/pause.rb +24 -0
- data/lib/tty-spinner/examples/run.rb +20 -0
- data/lib/tty-spinner/examples/success.rb +11 -0
- data/lib/tty-spinner/examples/threaded.rb +13 -0
- data/lib/tty-spinner/examples/update.rb +13 -0
- data/lib/tty-spinner/lib/tty/spinner/formats.rb +274 -0
- data/lib/tty-spinner/lib/tty/spinner/multi.rb +352 -0
- data/lib/tty-spinner/lib/tty/spinner/version.rb +7 -0
- data/lib/tty-spinner/lib/tty/spinner.rb +604 -0
- data/lib/tty-spinner/lib/tty-spinner.rb +2 -0
- data/lib/tty-spinner/spec/spec_helper.rb +52 -0
- data/lib/tty-spinner/spec/unit/auto_spin_spec.rb +25 -0
- data/lib/tty-spinner/spec/unit/clear_spec.rb +16 -0
- data/lib/tty-spinner/spec/unit/error_spec.rb +53 -0
- data/lib/tty-spinner/spec/unit/events_spec.rb +35 -0
- data/lib/tty-spinner/spec/unit/formats_spec.rb +9 -0
- data/lib/tty-spinner/spec/unit/frames_spec.rb +31 -0
- data/lib/tty-spinner/spec/unit/hide_cursor_spec.rb +51 -0
- data/lib/tty-spinner/spec/unit/job_spec.rb +12 -0
- data/lib/tty-spinner/spec/unit/join_spec.rb +10 -0
- data/lib/tty-spinner/spec/unit/log_spec.rb +60 -0
- data/lib/tty-spinner/spec/unit/multi/auto_spin_spec.rb +32 -0
- data/lib/tty-spinner/spec/unit/multi/error_spec.rb +107 -0
- data/lib/tty-spinner/spec/unit/multi/line_inset_spec.rb +57 -0
- data/lib/tty-spinner/spec/unit/multi/on_spec.rb +11 -0
- data/lib/tty-spinner/spec/unit/multi/register_spec.rb +46 -0
- data/lib/tty-spinner/spec/unit/multi/spin_spec.rb +101 -0
- data/lib/tty-spinner/spec/unit/multi/stop_spec.rb +95 -0
- data/lib/tty-spinner/spec/unit/multi/success_spec.rb +108 -0
- data/lib/tty-spinner/spec/unit/new_spec.rb +25 -0
- data/lib/tty-spinner/spec/unit/pause_spec.rb +43 -0
- data/lib/tty-spinner/spec/unit/reset_spec.rb +19 -0
- data/lib/tty-spinner/spec/unit/run_spec.rb +30 -0
- data/lib/tty-spinner/spec/unit/spin_spec.rb +117 -0
- data/lib/tty-spinner/spec/unit/stop_spec.rb +88 -0
- data/lib/tty-spinner/spec/unit/success_spec.rb +53 -0
- data/lib/tty-spinner/spec/unit/tty_spec.rb +8 -0
- data/lib/tty-spinner/spec/unit/update_spec.rb +85 -0
- data/lib/tty-spinner/tasks/console.rake +11 -0
- data/lib/tty-spinner/tasks/coverage.rake +11 -0
- data/lib/tty-spinner/tasks/spec.rake +29 -0
- data/lib/tty-spinner/tty-spinner.gemspec +36 -0
- data/planter-cli.gemspec +1 -0
- data/scripts/runtests.sh +1 -1
- data/spec/cli_spec.rb +27 -0
- data/spec/planter/hash_spec.rb +27 -0
- data/spec/planter_spec.rb +15 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/templates/test/%%project:snake%%.rtf +10 -0
- data/spec/templates/test/Rakefile +6 -0
- data/spec/templates/test/_planter.yml +3 -6
- data/spec/templates/test/test.rb +5 -0
- data/src/_README.md +20 -3
- metadata +108 -3
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "monitor"
|
|
4
|
+
require "forwardable"
|
|
5
|
+
|
|
6
|
+
require_relative "../spinner"
|
|
7
|
+
|
|
8
|
+
module TTY
|
|
9
|
+
class Spinner
|
|
10
|
+
# Used for managing multiple terminal spinners
|
|
11
|
+
#
|
|
12
|
+
# @api public
|
|
13
|
+
class Multi
|
|
14
|
+
include Enumerable
|
|
15
|
+
include MonitorMixin
|
|
16
|
+
|
|
17
|
+
extend Forwardable
|
|
18
|
+
|
|
19
|
+
def_delegators :@spinners, :each, :empty?, :length
|
|
20
|
+
|
|
21
|
+
DEFAULT_INSET = {
|
|
22
|
+
top: Gem.win_platform? ? "+ " : "\u250c ",
|
|
23
|
+
middle: Gem.win_platform? ? "|-- " : "\u251c\u2500\u2500 ",
|
|
24
|
+
bottom: Gem.win_platform? ? "|__ " : "\u2514\u2500\u2500 "
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
# The current count of all rendered rows
|
|
28
|
+
#
|
|
29
|
+
# @api public
|
|
30
|
+
attr_reader :rows
|
|
31
|
+
|
|
32
|
+
# Initialize a multispinner
|
|
33
|
+
#
|
|
34
|
+
# @example
|
|
35
|
+
# spinner = TTY::Spinner::Multi.new
|
|
36
|
+
#
|
|
37
|
+
# @param [String] message
|
|
38
|
+
# the optional message to print in front of the top level spinner
|
|
39
|
+
#
|
|
40
|
+
# @param [Hash] options
|
|
41
|
+
# @option options [Hash] :style
|
|
42
|
+
# keys :top :middle and :bottom can contain Strings that are used to
|
|
43
|
+
# indent the spinners. Ignored if message is blank
|
|
44
|
+
# @option options [Object] :output
|
|
45
|
+
# the object that responds to print call defaulting to stderr
|
|
46
|
+
# @option options [Boolean] :hide_cursor
|
|
47
|
+
# display or hide cursor
|
|
48
|
+
# @option options [Boolean] :clear
|
|
49
|
+
# clear ouptut when finished
|
|
50
|
+
# @option options [Float] :interval
|
|
51
|
+
# the interval for auto spinning
|
|
52
|
+
#
|
|
53
|
+
# @api public
|
|
54
|
+
def initialize(*args)
|
|
55
|
+
super()
|
|
56
|
+
@options = args.last.is_a?(::Hash) ? args.pop : {}
|
|
57
|
+
message = args.empty? ? nil : args.pop
|
|
58
|
+
@inset_opts = @options.delete(:style) { DEFAULT_INSET }
|
|
59
|
+
@rows = 0
|
|
60
|
+
@spinners = []
|
|
61
|
+
@spinners_count = 0
|
|
62
|
+
@top_spinner = nil
|
|
63
|
+
@last_spin_at = nil
|
|
64
|
+
unless message.nil?
|
|
65
|
+
@top_spinner = register(message, observable: false, row: next_row)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
@callbacks = {
|
|
69
|
+
success: [],
|
|
70
|
+
error: [],
|
|
71
|
+
done: [],
|
|
72
|
+
spin: []
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Register a new spinner
|
|
77
|
+
#
|
|
78
|
+
# @param [String, TTY::Spinner] pattern_or_spinner
|
|
79
|
+
# the pattern used for creating spinner, or a spinner instance
|
|
80
|
+
#
|
|
81
|
+
# @api public
|
|
82
|
+
def register(pattern_or_spinner, **options, &job)
|
|
83
|
+
observable = options.delete(:observable) { true }
|
|
84
|
+
spinner = nil
|
|
85
|
+
|
|
86
|
+
synchronize do
|
|
87
|
+
spinner = create_spinner(pattern_or_spinner, options)
|
|
88
|
+
spinner.attach_to(self)
|
|
89
|
+
spinner.job(&job) if block_given?
|
|
90
|
+
observe(spinner) if observable
|
|
91
|
+
@spinners << spinner
|
|
92
|
+
@spinners_count += 1
|
|
93
|
+
if @top_spinner
|
|
94
|
+
@spinners.each { |sp| sp.redraw_indent if sp.spinning? || sp.done? }
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
spinner
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Create a spinner instance
|
|
102
|
+
#
|
|
103
|
+
# @api private
|
|
104
|
+
def create_spinner(pattern_or_spinner, options)
|
|
105
|
+
case pattern_or_spinner
|
|
106
|
+
when ::String
|
|
107
|
+
TTY::Spinner.new(
|
|
108
|
+
pattern_or_spinner,
|
|
109
|
+
@options.merge(options)
|
|
110
|
+
)
|
|
111
|
+
when ::TTY::Spinner
|
|
112
|
+
pattern_or_spinner
|
|
113
|
+
else
|
|
114
|
+
raise ArgumentError, "Expected a pattern or spinner, " \
|
|
115
|
+
"got: #{pattern_or_spinner.class}"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Increase a row count
|
|
120
|
+
#
|
|
121
|
+
# @api public
|
|
122
|
+
def next_row
|
|
123
|
+
synchronize do
|
|
124
|
+
@rows += 1
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Get the top level spinner if it exists
|
|
129
|
+
#
|
|
130
|
+
# @return [TTY::Spinner] the top level spinner
|
|
131
|
+
#
|
|
132
|
+
# @api public
|
|
133
|
+
def top_spinner
|
|
134
|
+
raise "No top level spinner" if @top_spinner.nil?
|
|
135
|
+
|
|
136
|
+
@top_spinner
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Auto spin the top level spinner & all child spinners
|
|
140
|
+
# that have scheduled jobs
|
|
141
|
+
#
|
|
142
|
+
# @api public
|
|
143
|
+
def auto_spin
|
|
144
|
+
raise "No top level spinner" if @top_spinner.nil?
|
|
145
|
+
|
|
146
|
+
jobs = []
|
|
147
|
+
@spinners.each do |spinner|
|
|
148
|
+
if spinner.job?
|
|
149
|
+
spinner.auto_spin
|
|
150
|
+
jobs << Thread.new { spinner.execute_job }
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
jobs.each(&:join)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Perform a single spin animation
|
|
157
|
+
#
|
|
158
|
+
# @api public
|
|
159
|
+
def spin
|
|
160
|
+
raise "No top level spinner" if @top_spinner.nil?
|
|
161
|
+
|
|
162
|
+
synchronize do
|
|
163
|
+
throttle { @top_spinner.spin }
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Pause all spinners
|
|
168
|
+
#
|
|
169
|
+
# @api public
|
|
170
|
+
def pause
|
|
171
|
+
@spinners.dup.each(&:pause)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Resume all spinners
|
|
175
|
+
#
|
|
176
|
+
# @api public
|
|
177
|
+
def resume
|
|
178
|
+
@spinners.dup.each(&:resume)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Find the number of characters to move into the line
|
|
182
|
+
# before printing the spinner
|
|
183
|
+
#
|
|
184
|
+
# @param [Integer] line_no
|
|
185
|
+
# the current spinner line number for which line inset is calculated
|
|
186
|
+
#
|
|
187
|
+
# @return [String]
|
|
188
|
+
# the inset
|
|
189
|
+
#
|
|
190
|
+
# @api public
|
|
191
|
+
def line_inset(line_no)
|
|
192
|
+
return "" if @top_spinner.nil?
|
|
193
|
+
|
|
194
|
+
if line_no == 1
|
|
195
|
+
@inset_opts[:top]
|
|
196
|
+
elsif line_no == @spinners_count
|
|
197
|
+
@inset_opts[:bottom]
|
|
198
|
+
else
|
|
199
|
+
@inset_opts[:middle]
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Check if all spinners are done
|
|
204
|
+
#
|
|
205
|
+
# @return [Boolean]
|
|
206
|
+
#
|
|
207
|
+
# @api public
|
|
208
|
+
def done?
|
|
209
|
+
synchronize do
|
|
210
|
+
(@spinners - [@top_spinner]).all?(&:done?)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Check if all spinners succeeded
|
|
215
|
+
#
|
|
216
|
+
# @return [Boolean]
|
|
217
|
+
#
|
|
218
|
+
# @api public
|
|
219
|
+
def success?
|
|
220
|
+
synchronize do
|
|
221
|
+
(@spinners - [@top_spinner]).all?(&:success?)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Check if any spinner errored
|
|
226
|
+
#
|
|
227
|
+
# @return [Boolean]
|
|
228
|
+
#
|
|
229
|
+
# @api public
|
|
230
|
+
def error?
|
|
231
|
+
synchronize do
|
|
232
|
+
(@spinners - [@top_spinner]).any?(&:error?)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Stop all spinners
|
|
237
|
+
#
|
|
238
|
+
# @api public
|
|
239
|
+
def stop
|
|
240
|
+
@spinners.dup.each(&:stop)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Stop all spinners with success status
|
|
244
|
+
#
|
|
245
|
+
# @api public
|
|
246
|
+
def success
|
|
247
|
+
@spinners.dup.each(&:success)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Stop all spinners with error status
|
|
251
|
+
#
|
|
252
|
+
# @api public
|
|
253
|
+
def error
|
|
254
|
+
@spinners.dup.each(&:error)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Listen on event
|
|
258
|
+
#
|
|
259
|
+
# @api public
|
|
260
|
+
def on(key, &callback)
|
|
261
|
+
unless @callbacks.key?(key)
|
|
262
|
+
raise ArgumentError, "The event #{key} does not exist. " \
|
|
263
|
+
" Use :spin, :success, :error, or :done instead"
|
|
264
|
+
end
|
|
265
|
+
@callbacks[key] << callback
|
|
266
|
+
self
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
private
|
|
270
|
+
|
|
271
|
+
# Check if this spinner should revolve to keep constant speed
|
|
272
|
+
# matching top spinner interval
|
|
273
|
+
#
|
|
274
|
+
# @api private
|
|
275
|
+
def throttle
|
|
276
|
+
sleep_time = 1.0 / @top_spinner.interval
|
|
277
|
+
return if @last_spin_at && Time.now - @last_spin_at < sleep_time
|
|
278
|
+
|
|
279
|
+
yield if block_given?
|
|
280
|
+
@last_spin_at = Time.now
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Fire an event
|
|
284
|
+
#
|
|
285
|
+
# @api private
|
|
286
|
+
def emit(key, *args)
|
|
287
|
+
@callbacks[key].each do |block|
|
|
288
|
+
block.call(*args)
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Observe spinner for events to notify top spinner of current state
|
|
293
|
+
#
|
|
294
|
+
# @param [TTY::Spinner] spinner
|
|
295
|
+
# the spinner to listen to for events
|
|
296
|
+
#
|
|
297
|
+
# @api private
|
|
298
|
+
def observe(spinner)
|
|
299
|
+
spinner.on(:spin, &spin_handler)
|
|
300
|
+
.on(:success, &success_handler)
|
|
301
|
+
.on(:error, &error_handler)
|
|
302
|
+
.on(:done, &done_handler)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Handle spin event
|
|
306
|
+
#
|
|
307
|
+
# @api private
|
|
308
|
+
def spin_handler
|
|
309
|
+
proc do
|
|
310
|
+
spin if @top_spinner
|
|
311
|
+
emit(:spin)
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# Handle the success state
|
|
316
|
+
#
|
|
317
|
+
# @api private
|
|
318
|
+
def success_handler
|
|
319
|
+
proc do
|
|
320
|
+
if success?
|
|
321
|
+
@top_spinner.success if @top_spinner
|
|
322
|
+
emit(:success)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Handle the error state
|
|
328
|
+
#
|
|
329
|
+
# @api private
|
|
330
|
+
def error_handler
|
|
331
|
+
proc do
|
|
332
|
+
if error?
|
|
333
|
+
@top_spinner.error if @top_spinner
|
|
334
|
+
@fired ||= emit(:error) # fire once
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Handle the done state
|
|
340
|
+
#
|
|
341
|
+
# @api private
|
|
342
|
+
def done_handler
|
|
343
|
+
proc do
|
|
344
|
+
if done?
|
|
345
|
+
@top_spinner.stop if @top_spinner && !error? && !success?
|
|
346
|
+
emit(:done)
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end # MultiSpinner
|
|
351
|
+
end # Spinner
|
|
352
|
+
end # TTY
|