toys-core 0.19.1 → 0.21.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +56 -0
- data/README.md +3 -3
- data/lib/toys/cli.rb +1 -1
- data/lib/toys/compat.rb +63 -0
- data/lib/toys/core.rb +1 -1
- data/lib/toys/errors.rb +12 -11
- data/lib/toys/settings.rb +37 -14
- data/lib/toys/standard_middleware/show_help.rb +8 -8
- data/lib/toys/standard_middleware/show_root_version.rb +1 -1
- data/lib/toys/standard_mixins/bundler.rb +60 -9
- data/lib/toys/standard_mixins/exec.rb +81 -43
- data/lib/toys/standard_mixins/xdg.rb +1 -1
- data/lib/toys/utils/completion_engine.rb +88 -32
- data/lib/toys/utils/exec.rb +297 -125
- data/lib/toys/utils/gems.rb +132 -89
- data/lib/toys/utils/git_cache.rb +170 -90
- data/lib/toys/utils/pager.rb +5 -1
- data/lib/toys/utils/xdg.rb +143 -23
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2805bf71091b4ea8bf6f6a670281171dc6a5df4edec5196d80d64124ce2a199
|
|
4
|
+
data.tar.gz: b5c860449af3a0566e9b1fe8dc527cba4df6750ccc3b259365faf99fa79682fb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 95490a978d1a3ae04be668a2fd318de2499e9610bb6072a053776fb47214d2444c0d93a73fa690b46a6d4706e2fec1f20b76f8d111100ec65216f0c274efe77a
|
|
7
|
+
data.tar.gz: b9421ebfa989c45444024222cc3576a166d5797d7c982033265a11aa149c71ef0ab069441c70da490819e5bbafe95eb017c92289d6b46d7917c19634ee3eaf64
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,61 @@
|
|
|
1
1
|
# Release History
|
|
2
2
|
|
|
3
|
+
### v0.21.0 / 2026-03-23
|
|
4
|
+
|
|
5
|
+
This release includes a variety of small fixes and updates toward improving product polish in preparation for a 1.0 release. It focuses on the following areas:
|
|
6
|
+
|
|
7
|
+
* Updates to the help system
|
|
8
|
+
* FIXED / BREAKING CHANGE: The help middleware omits the subtool filter flags on runnable tools that have subtools
|
|
9
|
+
* Updates to bundler integration
|
|
10
|
+
* FIXED: Fixed some cleanup issues when bundler setup fails
|
|
11
|
+
* Updates to the exec utility
|
|
12
|
+
* ADDED: Support for the `:unbundle` option which removes any existing bundle for a subprocess
|
|
13
|
+
* FIXED: Fixed several thread-safety issues with the controller
|
|
14
|
+
* FIXED: The result callback is now called in background mode if the result is never explicitly obtained from the controller
|
|
15
|
+
* Updates to the git_cache utility
|
|
16
|
+
* ADDED: Support for filtering lookups of ref and source info
|
|
17
|
+
* ADDED: Support for SHA-256 repos
|
|
18
|
+
* FIXED: Fixed failure to get a parent directory after previously getting a descendant object
|
|
19
|
+
* FIXED: GitCache no longer unnecessarily sets the write bit on files copied into a specified directory
|
|
20
|
+
* FIXED: GitCache no longer cleans out existing files when writing to a shared source, which should reduce issues with concurrent clients
|
|
21
|
+
* Updates to the XDG utility
|
|
22
|
+
* FIXED / BREAKING CHANGE: The XDG utility returns an empty array (instead of the system defaults) from the corresponding methods if `XDG_DATA_DIRS` or `XDG_CONFIG_DIRS` is nonempty but contains only relative paths
|
|
23
|
+
* ADDED: Provided `lookup_state` and `lookup_cache` methods on the XDG utility
|
|
24
|
+
* Updates to the settings system:
|
|
25
|
+
* FIXED: Block certain reserved names from being used as Settings field names
|
|
26
|
+
* FIXED: Fixed `Settings#load_data!` when subclassing another settings class
|
|
27
|
+
* FIXED: Reject non-String values in Settings regexp type spec
|
|
28
|
+
* FIXED: Settings guards against unknown classes when loading YAML on older Ruby versions
|
|
29
|
+
* FIXED: Settings guards against `ILLEGAL_VALUE` being passed to `range.member?`
|
|
30
|
+
* FIXED: Settings does a better job choosing exact-match values when using a union type
|
|
31
|
+
* FIXED: Settings reject non-numeric strings in Integer and Float converters
|
|
32
|
+
* FIXED: Settings propagates nested group errors in `Settings#load_data!`
|
|
33
|
+
|
|
34
|
+
### v0.20.0 / 2026-03-09
|
|
35
|
+
|
|
36
|
+
Toys-core 0.20 is a major release with several new features and a number of fixes, including a few minor breaking changes.
|
|
37
|
+
|
|
38
|
+
Major changes:
|
|
39
|
+
|
|
40
|
+
* NEW: Native tab completion for zsh.
|
|
41
|
+
* NEW: The `:bundler` mixin supports "manual" bundle setup, allowing bundler decisions to be deferred to execution time
|
|
42
|
+
|
|
43
|
+
Updates to the Exec mixin and library:
|
|
44
|
+
|
|
45
|
+
* NEW: The new `Toys::Utils::Exec::Result#effective_result` method provides a reasonable integer result code even when a process terminates via signal or fails to start at all.
|
|
46
|
+
* BREAKING API CHANGE: `:cli` is no longer a legal config option.
|
|
47
|
+
* BREAKING API CHANGE: An options hash is no longer passed to the proc when executing a proc using a fork.
|
|
48
|
+
* BREAKING API CHANGE: Passing an IO object as an input or output stream no longer closes it afterward.
|
|
49
|
+
* BREAKING API CHANGE: `Toys::Utils::Exec::Controller#result` no longer preemptively (and prematurely) closes the controller input stream
|
|
50
|
+
* FIXED: The `:unsetenv_others` option now works properly when executing a proc using a fork.
|
|
51
|
+
* FIXED: Environment variable values specified as nil are now correctly unset when executing a proc using a fork.
|
|
52
|
+
* FIXED: Fixed a rare concurrency issue if multiple threads concurrently get the result from a controller.
|
|
53
|
+
|
|
54
|
+
Minor fixes for TruffleRuby compatibility:
|
|
55
|
+
|
|
56
|
+
* FIXED: The `:bundler` mixin will not attempt to add the `pathname` gem to generated Gemfiles when running on TruffleRuby. This caused issues because TruffleRuby includes a special version of the gem and cannot install the one from Rubygems.
|
|
57
|
+
* FIXED: `ContextualError` no longer overrides `Exception#cause`, which could confuse TruffleRuby.
|
|
58
|
+
|
|
3
59
|
### v0.19.1 / 2026-01-06
|
|
4
60
|
|
|
5
61
|
* DOCS: Some formatting fixes in the user guide
|
data/README.md
CHANGED
|
@@ -265,8 +265,8 @@ Navigate to the simple-gem example:
|
|
|
265
265
|
|
|
266
266
|
$ cd toys-core/examples/simple-gem
|
|
267
267
|
|
|
268
|
-
This example wraps the simple "greet" executable that we
|
|
269
|
-
|
|
268
|
+
This example wraps the simple "greet" executable that we covered earlier, in a
|
|
269
|
+
gem. You can see the
|
|
270
270
|
[executable file](https://github.com/dazuma/toys/tree/main/toys-core/examples/simple-gem/bin/toys-core-simple-example)
|
|
271
271
|
in the bin directory.
|
|
272
272
|
|
|
@@ -348,7 +348,7 @@ recommended because it has a few known bugs that affect Toys.
|
|
|
348
348
|
|
|
349
349
|
## License
|
|
350
350
|
|
|
351
|
-
Copyright 2019-
|
|
351
|
+
Copyright 2019-2026 Daniel Azuma and the Toys contributors
|
|
352
352
|
|
|
353
353
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
354
354
|
of this software and associated documentation files (the "Software"), to deal
|
data/lib/toys/cli.rb
CHANGED
|
@@ -552,7 +552,7 @@ module Toys
|
|
|
552
552
|
#
|
|
553
553
|
def default_error_handler
|
|
554
554
|
proc do |error|
|
|
555
|
-
cause = error.cause
|
|
555
|
+
cause = error.respond_to?(:underlying_error) ? error.underlying_error : error.cause
|
|
556
556
|
raise cause.is_a?(::SignalException) ? cause : error
|
|
557
557
|
end
|
|
558
558
|
end
|
data/lib/toys/compat.rb
CHANGED
|
@@ -13,35 +13,72 @@ module Toys
|
|
|
13
13
|
parts = ::RUBY_VERSION.split(".")
|
|
14
14
|
ruby_version = (parts[0].to_i * 10000) + (parts[1].to_i * 100) + parts[2].to_i
|
|
15
15
|
|
|
16
|
+
##
|
|
16
17
|
# @private
|
|
18
|
+
# An integer representation of the Ruby version, guaranteed to have the
|
|
19
|
+
# correct ordering. Currently, this is `major*10000 + minor*100 + patch`.
|
|
20
|
+
#
|
|
21
|
+
# @return [Integer]
|
|
22
|
+
#
|
|
17
23
|
RUBY_VERSION_CODE = ruby_version
|
|
18
24
|
|
|
25
|
+
##
|
|
19
26
|
# @private
|
|
27
|
+
# Whether the current Ruby implementation is JRuby
|
|
28
|
+
#
|
|
29
|
+
# @return [boolean]
|
|
30
|
+
#
|
|
20
31
|
def self.jruby?
|
|
21
32
|
::RUBY_ENGINE == "jruby"
|
|
22
33
|
end
|
|
23
34
|
|
|
35
|
+
##
|
|
24
36
|
# @private
|
|
37
|
+
# Whether the current Ruby implementation is TruffleRuby
|
|
38
|
+
#
|
|
39
|
+
# @return [boolean]
|
|
40
|
+
#
|
|
25
41
|
def self.truffleruby?
|
|
26
42
|
::RUBY_ENGINE == "truffleruby"
|
|
27
43
|
end
|
|
28
44
|
|
|
45
|
+
##
|
|
29
46
|
# @private
|
|
47
|
+
# Whether we are running on Windows
|
|
48
|
+
#
|
|
49
|
+
# @return [boolean]
|
|
50
|
+
#
|
|
30
51
|
def self.windows?
|
|
31
52
|
::RbConfig::CONFIG["host_os"] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
|
32
53
|
end
|
|
33
54
|
|
|
55
|
+
##
|
|
34
56
|
# @private
|
|
57
|
+
# Whether we are running on Mac OS
|
|
58
|
+
#
|
|
59
|
+
# @return [boolean]
|
|
60
|
+
#
|
|
35
61
|
def self.macos?
|
|
36
62
|
::RbConfig::CONFIG["host_os"] =~ /darwin/
|
|
37
63
|
end
|
|
38
64
|
|
|
65
|
+
##
|
|
39
66
|
# @private
|
|
67
|
+
# Whether fork is supported on the current Ruby and OS
|
|
68
|
+
#
|
|
69
|
+
# @return [boolean]
|
|
70
|
+
#
|
|
40
71
|
def self.allow_fork?
|
|
41
72
|
!jruby? && !truffleruby? && !windows?
|
|
42
73
|
end
|
|
43
74
|
|
|
75
|
+
##
|
|
44
76
|
# @private
|
|
77
|
+
# Whether it is possible to get suggestions from DidYouMean. If this
|
|
78
|
+
# returns false, {Compat.suggestions} will always return the empty array.
|
|
79
|
+
#
|
|
80
|
+
# @return [boolean]
|
|
81
|
+
#
|
|
45
82
|
def self.supports_suggestions?
|
|
46
83
|
unless defined?(@supports_suggestions)
|
|
47
84
|
begin
|
|
@@ -59,7 +96,16 @@ module Toys
|
|
|
59
96
|
@supports_suggestions
|
|
60
97
|
end
|
|
61
98
|
|
|
99
|
+
##
|
|
62
100
|
# @private
|
|
101
|
+
# A list of suggestions from DidYouMean.
|
|
102
|
+
#
|
|
103
|
+
# @param word [String] A value that seems wrong
|
|
104
|
+
# @param list [Array<String>] A list of valid values
|
|
105
|
+
#
|
|
106
|
+
# @return [Array<String>] A possibly empty array of suggestions from the
|
|
107
|
+
# valid list that could match the given word.
|
|
108
|
+
#
|
|
63
109
|
def self.suggestions(word, list)
|
|
64
110
|
if supports_suggestions?
|
|
65
111
|
::DidYouMean::SpellChecker.new(dictionary: list).correct(word)
|
|
@@ -67,5 +113,22 @@ module Toys
|
|
|
67
113
|
[]
|
|
68
114
|
end
|
|
69
115
|
end
|
|
116
|
+
|
|
117
|
+
##
|
|
118
|
+
# @private
|
|
119
|
+
# A list of gems that should generally not be included in a bundle, usually
|
|
120
|
+
# because the Ruby implementation handles the library specially and cannot
|
|
121
|
+
# install the real gem. Currently, this includes the `pathname` gem for
|
|
122
|
+
# TruffleRuby, since TruffleRuby includes a special version of it.
|
|
123
|
+
#
|
|
124
|
+
# @return [Array<String>]
|
|
125
|
+
#
|
|
126
|
+
def self.gems_to_omit_from_bundles
|
|
127
|
+
if truffleruby?
|
|
128
|
+
["pathname"]
|
|
129
|
+
else
|
|
130
|
+
[]
|
|
131
|
+
end
|
|
132
|
+
end
|
|
70
133
|
end
|
|
71
134
|
end
|
data/lib/toys/core.rb
CHANGED
data/lib/toys/errors.rb
CHANGED
|
@@ -51,24 +51,25 @@ module Toys
|
|
|
51
51
|
#
|
|
52
52
|
# @private This interface is internal and subject to change without warning.
|
|
53
53
|
#
|
|
54
|
-
def initialize(
|
|
54
|
+
def initialize(underlying_error, banner,
|
|
55
55
|
config_path: nil, config_line: nil,
|
|
56
56
|
tool_name: nil, tool_args: nil)
|
|
57
|
-
super("#{banner} : #{
|
|
58
|
-
@
|
|
57
|
+
super("#{banner} : #{underlying_error.message} (#{underlying_error.class})")
|
|
58
|
+
@underlying_error = underlying_error
|
|
59
59
|
@banner = banner
|
|
60
60
|
@config_path = config_path
|
|
61
61
|
@config_line = config_line
|
|
62
62
|
@tool_name = tool_name
|
|
63
63
|
@tool_args = tool_args
|
|
64
|
-
set_backtrace(
|
|
64
|
+
set_backtrace(underlying_error.backtrace)
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
##
|
|
68
|
-
# The underlying exception
|
|
68
|
+
# The underlying exception.
|
|
69
|
+
# Generally the same as `Exception#cause`.
|
|
69
70
|
# @return [::StandardError]
|
|
70
71
|
#
|
|
71
|
-
attr_reader :
|
|
72
|
+
attr_reader :underlying_error
|
|
72
73
|
|
|
73
74
|
##
|
|
74
75
|
# An overall banner message
|
|
@@ -141,10 +142,10 @@ module Toys
|
|
|
141
142
|
end
|
|
142
143
|
raise e
|
|
143
144
|
rescue ::ScriptError, ::StandardError, ::SignalException => e
|
|
144
|
-
|
|
145
|
-
add_fields_if_missing(
|
|
146
|
-
add_config_path_if_missing(
|
|
147
|
-
raise
|
|
145
|
+
ce = ContextualError.new(e, banner)
|
|
146
|
+
add_fields_if_missing(ce, opts)
|
|
147
|
+
add_config_path_if_missing(ce, path)
|
|
148
|
+
raise ce
|
|
148
149
|
end
|
|
149
150
|
|
|
150
151
|
##
|
|
@@ -172,7 +173,7 @@ module Toys
|
|
|
172
173
|
|
|
173
174
|
def add_config_path_if_missing(error, path)
|
|
174
175
|
if error.config_path.nil? && error.config_line.nil?
|
|
175
|
-
l = (error.
|
|
176
|
+
l = (error.underlying_error.backtrace_locations || []).find do |b|
|
|
176
177
|
b.absolute_path == path || b.path == path
|
|
177
178
|
end
|
|
178
179
|
if l
|
data/lib/toys/settings.rb
CHANGED
|
@@ -35,8 +35,12 @@ module Toys
|
|
|
35
35
|
# Attribute names must start with an ascii letter, and may contain only ascii
|
|
36
36
|
# letters, digits, and underscores. Unlike method names, they may not include
|
|
37
37
|
# non-ascii unicode characters, nor may they end with `!` or `?`.
|
|
38
|
-
# Additionally,
|
|
39
|
-
#
|
|
38
|
+
# Additionally, some names are reserved because they would shadow critical
|
|
39
|
+
# Ruby methods or interfere with Settings' internal behavior (see
|
|
40
|
+
# {Toys::Settings::RESERVED_FIELD_NAMES} for the complete list, which
|
|
41
|
+
# currently includes names such as `class`, `clone`, `dup`, `freeze`, `hash`,
|
|
42
|
+
# `initialize`, `method_missing`, `object_id`, `public_send`, `raise`,
|
|
43
|
+
# `require`, and `send`).
|
|
40
44
|
#
|
|
41
45
|
# Each attribute defines four methods: a getter, a setter, an unsetter, and a
|
|
42
46
|
# set detector. In the above example, the attribute named `:endpoint` creates
|
|
@@ -297,12 +301,27 @@ module Toys
|
|
|
297
301
|
# grandchild_settings.str # => "value_from_root"
|
|
298
302
|
#
|
|
299
303
|
class Settings
|
|
304
|
+
##
|
|
300
305
|
# A special value indicating a type check failure.
|
|
306
|
+
#
|
|
301
307
|
ILLEGAL_VALUE = ::Object.new.freeze
|
|
302
308
|
|
|
309
|
+
##
|
|
303
310
|
# A special type specification indicating infer from the default value.
|
|
311
|
+
#
|
|
304
312
|
DEFAULT_TYPE = ::Object.new.freeze
|
|
305
313
|
|
|
314
|
+
##
|
|
315
|
+
# Field names that are not allowed because they would shadow critical Ruby
|
|
316
|
+
# methods or break Settings' own internal method calls.
|
|
317
|
+
#
|
|
318
|
+
# @return [Array<String>]
|
|
319
|
+
#
|
|
320
|
+
RESERVED_FIELD_NAMES = [
|
|
321
|
+
"class", "clone", "dup", "freeze", "hash", "initialize",
|
|
322
|
+
"method_missing", "object_id", "public_send", "raise", "require", "send"
|
|
323
|
+
].freeze
|
|
324
|
+
|
|
306
325
|
##
|
|
307
326
|
# Error raised when a value does not match the type constraint.
|
|
308
327
|
#
|
|
@@ -447,15 +466,14 @@ module Toys
|
|
|
447
466
|
range_class = (range.begin || range.end).class
|
|
448
467
|
new("(#{range})") do |val|
|
|
449
468
|
converted = convert(val, range_class)
|
|
450
|
-
range.member?(converted) ? converted : ILLEGAL_VALUE
|
|
469
|
+
converted != ILLEGAL_VALUE && range.member?(converted) ? converted : ILLEGAL_VALUE
|
|
451
470
|
end
|
|
452
471
|
end
|
|
453
472
|
|
|
454
473
|
def for_regexp(regexp)
|
|
455
474
|
regexp_str = regexp.source.gsub("/", "\\/")
|
|
456
475
|
new("/#{regexp_str}/") do |val|
|
|
457
|
-
|
|
458
|
-
regexp.match(str) ? str : ILLEGAL_VALUE
|
|
476
|
+
val.is_a?(::String) && regexp.match(val) ? val : ILLEGAL_VALUE
|
|
459
477
|
end
|
|
460
478
|
end
|
|
461
479
|
|
|
@@ -466,7 +484,7 @@ module Toys
|
|
|
466
484
|
result = ILLEGAL_VALUE
|
|
467
485
|
types.each do |type|
|
|
468
486
|
converted = type.call(val)
|
|
469
|
-
if converted
|
|
487
|
+
if converted.eql?(val)
|
|
470
488
|
result = val
|
|
471
489
|
break
|
|
472
490
|
elsif result == ILLEGAL_VALUE
|
|
@@ -518,7 +536,7 @@ module Toys
|
|
|
518
536
|
float_converter = proc do |val|
|
|
519
537
|
case val
|
|
520
538
|
when ::String
|
|
521
|
-
val
|
|
539
|
+
Float(val)
|
|
522
540
|
when ::Numeric
|
|
523
541
|
converted = val.to_f
|
|
524
542
|
converted == val ? converted : ILLEGAL_VALUE
|
|
@@ -530,7 +548,7 @@ module Toys
|
|
|
530
548
|
integer_converter = proc do |val|
|
|
531
549
|
case val
|
|
532
550
|
when ::String
|
|
533
|
-
val
|
|
551
|
+
Integer(val)
|
|
534
552
|
when ::Numeric
|
|
535
553
|
converted = val.to_i
|
|
536
554
|
converted == val ? converted : ILLEGAL_VALUE
|
|
@@ -605,7 +623,7 @@ module Toys
|
|
|
605
623
|
raise FieldError.new(value, self.class, name, nil) unless field
|
|
606
624
|
if field.group?
|
|
607
625
|
raise FieldError.new(value, self.class, name, "Hash") unless value.is_a?(::Hash)
|
|
608
|
-
get!(field).load_data!(value)
|
|
626
|
+
errors.concat(get!(field).load_data!(value, raise_on_failure: raise_on_failure))
|
|
609
627
|
else
|
|
610
628
|
set!(field, value)
|
|
611
629
|
end
|
|
@@ -628,7 +646,7 @@ module Toys
|
|
|
628
646
|
#
|
|
629
647
|
def load_yaml!(str, raise_on_failure: false)
|
|
630
648
|
require "psych"
|
|
631
|
-
load_data!(::Psych.
|
|
649
|
+
load_data!(::Psych.safe_load(str, permitted_classes: [::Symbol]), raise_on_failure: raise_on_failure)
|
|
632
650
|
end
|
|
633
651
|
|
|
634
652
|
##
|
|
@@ -641,7 +659,7 @@ module Toys
|
|
|
641
659
|
# @return [Array<FieldError>] An array of errors.
|
|
642
660
|
#
|
|
643
661
|
def load_yaml_file!(filename, raise_on_failure: false)
|
|
644
|
-
load_yaml!(File.read(filename), raise_on_failure: raise_on_failure)
|
|
662
|
+
load_yaml!(::File.read(filename), raise_on_failure: raise_on_failure)
|
|
645
663
|
end
|
|
646
664
|
|
|
647
665
|
##
|
|
@@ -668,7 +686,7 @@ module Toys
|
|
|
668
686
|
# @return [Array<FieldError>] An array of errors.
|
|
669
687
|
#
|
|
670
688
|
def load_json_file!(filename, raise_on_failure: false, **json_opts)
|
|
671
|
-
load_json!(File.read(filename), raise_on_failure: raise_on_failure, **json_opts)
|
|
689
|
+
load_json!(::File.read(filename), raise_on_failure: raise_on_failure, **json_opts)
|
|
672
690
|
end
|
|
673
691
|
|
|
674
692
|
##
|
|
@@ -848,7 +866,12 @@ module Toys
|
|
|
848
866
|
# all its instances.
|
|
849
867
|
#
|
|
850
868
|
def fields
|
|
851
|
-
@fields ||=
|
|
869
|
+
@fields ||=
|
|
870
|
+
if superclass.respond_to?(:fields)
|
|
871
|
+
superclass.fields.dup
|
|
872
|
+
else
|
|
873
|
+
{}
|
|
874
|
+
end
|
|
852
875
|
end
|
|
853
876
|
|
|
854
877
|
##
|
|
@@ -882,7 +905,7 @@ module Toys
|
|
|
882
905
|
|
|
883
906
|
def interpret_name(name)
|
|
884
907
|
name = name.to_s
|
|
885
|
-
if name !~ /^[a-zA-Z]\w*$/ || name
|
|
908
|
+
if name !~ /^[a-zA-Z]\w*$/ || RESERVED_FIELD_NAMES.include?(name)
|
|
886
909
|
raise ::ArgumentError, "Illegal settings field name: #{name}"
|
|
887
910
|
end
|
|
888
911
|
existing = public_instance_methods(false)
|
|
@@ -53,43 +53,43 @@ module Toys
|
|
|
53
53
|
# Key set when the show help flag is present
|
|
54
54
|
# @return [Object]
|
|
55
55
|
#
|
|
56
|
-
SHOW_HELP_KEY = Object.new.freeze
|
|
56
|
+
SHOW_HELP_KEY = ::Object.new.freeze
|
|
57
57
|
|
|
58
58
|
##
|
|
59
59
|
# Key set when the show usage flag is present
|
|
60
60
|
# @return [Object]
|
|
61
61
|
#
|
|
62
|
-
SHOW_USAGE_KEY = Object.new.freeze
|
|
62
|
+
SHOW_USAGE_KEY = ::Object.new.freeze
|
|
63
63
|
|
|
64
64
|
##
|
|
65
65
|
# Key set when the show subtool list flag is present
|
|
66
66
|
# @return [Object]
|
|
67
67
|
#
|
|
68
|
-
SHOW_LIST_KEY = Object.new.freeze
|
|
68
|
+
SHOW_LIST_KEY = ::Object.new.freeze
|
|
69
69
|
|
|
70
70
|
##
|
|
71
71
|
# Key for the recursive setting
|
|
72
72
|
# @return [Object]
|
|
73
73
|
#
|
|
74
|
-
RECURSIVE_SUBTOOLS_KEY = Object.new.freeze
|
|
74
|
+
RECURSIVE_SUBTOOLS_KEY = ::Object.new.freeze
|
|
75
75
|
|
|
76
76
|
##
|
|
77
77
|
# Key for the search string
|
|
78
78
|
# @return [Object]
|
|
79
79
|
#
|
|
80
|
-
SEARCH_STRING_KEY = Object.new.freeze
|
|
80
|
+
SEARCH_STRING_KEY = ::Object.new.freeze
|
|
81
81
|
|
|
82
82
|
##
|
|
83
83
|
# Key for the show-all-subtools setting
|
|
84
84
|
# @return [Object]
|
|
85
85
|
#
|
|
86
|
-
SHOW_ALL_SUBTOOLS_KEY = Object.new.freeze
|
|
86
|
+
SHOW_ALL_SUBTOOLS_KEY = ::Object.new.freeze
|
|
87
87
|
|
|
88
88
|
##
|
|
89
89
|
# Key for the tool name
|
|
90
90
|
# @return [Object]
|
|
91
91
|
#
|
|
92
|
-
TOOL_NAME_KEY = Object.new.freeze
|
|
92
|
+
TOOL_NAME_KEY = ::Object.new.freeze
|
|
93
93
|
|
|
94
94
|
##
|
|
95
95
|
# Create a ShowHelp middleware.
|
|
@@ -214,7 +214,7 @@ module Toys
|
|
|
214
214
|
list_flags = has_subtools ? add_list_flags(tool) : []
|
|
215
215
|
can_display_help = !help_flags.empty? || !list_flags.empty? ||
|
|
216
216
|
!usage_flags.empty? || @fallback_execution
|
|
217
|
-
if can_display_help && has_subtools
|
|
217
|
+
if can_display_help && has_subtools && !tool.runnable?
|
|
218
218
|
add_recursive_flags(tool)
|
|
219
219
|
add_search_flags(tool)
|
|
220
220
|
add_show_all_subtools_flags(tool)
|
|
@@ -22,9 +22,22 @@ module Toys
|
|
|
22
22
|
#
|
|
23
23
|
# The following parameters can be passed when including this mixin:
|
|
24
24
|
#
|
|
25
|
-
# * `:static` (Boolean)
|
|
26
|
-
#
|
|
27
|
-
#
|
|
25
|
+
# * `:static` (Boolean) Has the same effect as passing `:static` to the
|
|
26
|
+
# `:setup` parameter. This is present largely for historical
|
|
27
|
+
# compatibility, but it is supported and _not_ deprecated.
|
|
28
|
+
#
|
|
29
|
+
# * `:setup` (:auto,:manual,:static) A symbol indicating when the bundle
|
|
30
|
+
# should be installed. Possible values are:
|
|
31
|
+
#
|
|
32
|
+
# * `:auto` - (Default) Installs the bundle just before the tool runs.
|
|
33
|
+
# * `:static` - Installs the bundle immediately when defining the
|
|
34
|
+
# tool.
|
|
35
|
+
# * `:manual` - Does not install the bundle, but defines the methods
|
|
36
|
+
# `bundler_setup` and `bundler_setup?` in the tool. The tool can
|
|
37
|
+
# call `bundler_setup` to install the bundle, optionally passing
|
|
38
|
+
# any of the remaining keyword arguments below to override the
|
|
39
|
+
# corresponding mixin parameters. The `bundler_setup?` method can
|
|
40
|
+
# be queried to determine whether the bundle has been set up yet.
|
|
28
41
|
#
|
|
29
42
|
# * `:groups` (Array\<String\>) The groups to include in setup.
|
|
30
43
|
#
|
|
@@ -76,7 +89,9 @@ module Toys
|
|
|
76
89
|
# (optional)
|
|
77
90
|
#
|
|
78
91
|
# * `:terminal` (Toys::Utils::Terminal) Terminal to use (optional)
|
|
92
|
+
#
|
|
79
93
|
# * `:input` (IO) Input IO (optional, defaults to STDIN)
|
|
94
|
+
#
|
|
80
95
|
# * `:output` (IO) Output IO (optional, defaults to STDOUT)
|
|
81
96
|
#
|
|
82
97
|
module Bundler
|
|
@@ -94,6 +109,14 @@ module Toys
|
|
|
94
109
|
#
|
|
95
110
|
DEFAULT_TOYS_GEMFILE_NAMES = [".gems.rb", "Gemfile"].freeze
|
|
96
111
|
|
|
112
|
+
##
|
|
113
|
+
# @private
|
|
114
|
+
# Context key for the mixin parameters when using manual setup. The value
|
|
115
|
+
# will be a hash of parameters if the bundle has not been set up yet, or
|
|
116
|
+
# nil if the bundle has already been set up.
|
|
117
|
+
#
|
|
118
|
+
SETUP_PARAMS_KEY = ::Object.new.freeze
|
|
119
|
+
|
|
97
120
|
##
|
|
98
121
|
# @private
|
|
99
122
|
#
|
|
@@ -121,17 +144,45 @@ module Toys
|
|
|
121
144
|
gems.bundle(groups: groups, gemfile_path: gemfile_path, retries: retries)
|
|
122
145
|
end
|
|
123
146
|
|
|
124
|
-
on_initialize do |static: false, **kwargs|
|
|
125
|
-
|
|
147
|
+
on_initialize do |static: false, setup: nil, **kwargs|
|
|
148
|
+
setup ||= (static ? :static : :auto)
|
|
149
|
+
case setup
|
|
150
|
+
when :auto
|
|
126
151
|
context_directory = self[::Toys::Context::Key::CONTEXT_DIRECTORY]
|
|
127
152
|
source_info = self[::Toys::Context::Key::TOOL_SOURCE]
|
|
128
153
|
::Toys::StandardMixins::Bundler.setup_bundle(context_directory, source_info, **kwargs)
|
|
154
|
+
when :manual
|
|
155
|
+
self[::Toys::StandardMixins::Bundler::SETUP_PARAMS_KEY] = kwargs
|
|
156
|
+
when :static
|
|
157
|
+
# Already set up at include time
|
|
129
158
|
end
|
|
130
159
|
end
|
|
131
160
|
|
|
132
|
-
on_include do |static: false, **kwargs|
|
|
133
|
-
|
|
161
|
+
on_include do |static: false, setup: nil, **kwargs|
|
|
162
|
+
setup ||= (static ? :static : :auto)
|
|
163
|
+
case setup
|
|
164
|
+
when :static
|
|
134
165
|
::Toys::StandardMixins::Bundler.setup_bundle(context_directory, source_info, **kwargs)
|
|
166
|
+
when :manual
|
|
167
|
+
# @private Defined dynamically for the tool but not visible to YARD
|
|
168
|
+
def bundler_setup(**kwargs)
|
|
169
|
+
original_kwargs = self[::Toys::StandardMixins::Bundler::SETUP_PARAMS_KEY]
|
|
170
|
+
raise ::Toys::Utils::Gems::AlreadyBundledError unless original_kwargs
|
|
171
|
+
context_directory = self[::Toys::Context::Key::CONTEXT_DIRECTORY]
|
|
172
|
+
source_info = self[::Toys::Context::Key::TOOL_SOURCE]
|
|
173
|
+
final_kwargs = original_kwargs.merge(kwargs)
|
|
174
|
+
::Toys::StandardMixins::Bundler.setup_bundle(context_directory, source_info, **final_kwargs)
|
|
175
|
+
self[::Toys::StandardMixins::Bundler::SETUP_PARAMS_KEY] = nil
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# @private Defined dynamically for the tool but not visible to YARD
|
|
179
|
+
def bundler_setup?
|
|
180
|
+
self[::Toys::StandardMixins::Bundler::SETUP_PARAMS_KEY].nil?
|
|
181
|
+
end
|
|
182
|
+
when :auto
|
|
183
|
+
# Do nothing at this point
|
|
184
|
+
else
|
|
185
|
+
raise ::ArgumentError, "Unrecognized setup type: #{setup.inspect}"
|
|
135
186
|
end
|
|
136
187
|
end
|
|
137
188
|
|
|
@@ -145,7 +196,7 @@ module Toys
|
|
|
145
196
|
def initialize(context_directory, source_info, gemfile_names, toys_gemfile_names)
|
|
146
197
|
@context_directory = context_directory
|
|
147
198
|
@source_info = source_info
|
|
148
|
-
@gemfile_names = gemfile_names
|
|
199
|
+
@gemfile_names = gemfile_names || ::Toys::Utils::Gems::DEFAULT_GEMFILE_NAMES
|
|
149
200
|
@toys_gemfile_names = toys_gemfile_names || DEFAULT_TOYS_GEMFILE_NAMES
|
|
150
201
|
end
|
|
151
202
|
|
|
@@ -165,7 +216,7 @@ module Toys
|
|
|
165
216
|
when :toys
|
|
166
217
|
search_toys
|
|
167
218
|
else
|
|
168
|
-
raise ::ArgumentError, "Unrecognized search_dir: #{
|
|
219
|
+
raise ::ArgumentError, "Unrecognized search_dir: #{search_dir.inspect}"
|
|
169
220
|
end
|
|
170
221
|
end
|
|
171
222
|
|