toys 0.24.0 → 0.25.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 +30 -0
- data/README.md +4 -3
- data/bin/toys +8 -1
- data/core-docs/toys/cli.rb +4 -5
- data/core-docs/toys/core.rb +1 -1
- data/core-docs/toys/flag.rb +4 -2
- data/core-docs/toys/runner.rb +11 -1
- data/core-docs/toys/standard_middleware/handle_usage_errors.rb +3 -2
- data/core-docs/toys/standard_middleware/show_help.rb +4 -3
- data/core-docs/toys/standard_mixins/highline.rb +5 -0
- data/core-docs/toys/utils/git_cache.rb +6 -3
- data/core-docs/toys/utils/pager.rb +33 -4
- data/core-docs/toys/utils/standard_ui.rb +109 -7
- data/core-docs/toys/utils/terminal.rb +43 -1
- data/core-docs/toys/utils/xdg.rb +7 -1
- data/core-docs/toys/warnings.rb +96 -0
- data/core-docs/toys-core.rb +2 -1
- data/docs/guide.md +43 -7
- data/lib/toys/standard_cli.rb +183 -28
- data/lib/toys/version.rb +1 -1
- data/share/bash-completion.sh +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e494ced1b44b862aee77dd732210549374c571b55b4da8d503034ef3f87bba6f
|
|
4
|
+
data.tar.gz: bceadfc53e8b691951eef4ea4ef6d8b2f666590f745185322577d4bb5ccff82e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 40b86310b2d3ad6ce6b16ba738f4d8f543943f008a41b77fdc91b8f858afe50fa2104b3adebb2719aba98e6e920ce7f86f5df00a3c9d8824b4ea85e395fa5710
|
|
7
|
+
data.tar.gz: e468cd88b4042956bf12cbead2316c592799e667d61299ae69ab66d7cf457f5cef727a3d3cbb1589c3bf3cc16d76a89f8e8c4fff036a343fc6ad5a488456c2c9
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Release History
|
|
2
2
|
|
|
3
|
+
### v0.25.0 / 2026-10-10
|
|
4
|
+
|
|
5
|
+
This is a release candidate release toward version 1.0. It includes a variety of fixes and small features, largely around adherence to clig.dev and other common CLI guidelines.
|
|
6
|
+
|
|
7
|
+
* Major updates
|
|
8
|
+
* ADDED: The `-h` flag is now a standard help flag, similar to `--help`.
|
|
9
|
+
* Updates to tool lookup
|
|
10
|
+
* ADDED: Toys now loads global tools from the XDG config directories
|
|
11
|
+
* ADDED: The `TOYS_GLOBAL_SOURCES` environment variable selects which global sources are searched
|
|
12
|
+
* BREAKING CHANGE: The `TOYS_PATH` environment variable is no longer supported. Use `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`, or `TOYS_GLOBAL_SOURCES` instead.
|
|
13
|
+
* BREAKING CHANGE: Toys no longer loads global tools from `/etc/.toys.rb` or `/etc/.toys/`. Move them into `/etc/xdg/toys` instead.
|
|
14
|
+
* BREAKING CHANGE: Removed the `Toys::StandardCLI::TOYS_PATH_ENV` constant.
|
|
15
|
+
* Updates to logging and warnings
|
|
16
|
+
* ADDED: Warnings are displayed when a tool invokes a deprecated interface. They can be turned off by setting `TOYS_SUPPRESS_WARNINGS` to a nonempty value.
|
|
17
|
+
* ADDED: Logs display with a simplified severity prefix unless verbosity is positive
|
|
18
|
+
* FIXED: The `DEBUG` log prefix is no longer colored white
|
|
19
|
+
* FIXED: Logs emitted from tool initializers honor the verbosity
|
|
20
|
+
* Updates to ANSI coloring control
|
|
21
|
+
* ADDED: The `FORCE_COLOR` environment variable forces styled output on, or off when set to 0 or false
|
|
22
|
+
* FIXED: An empty `NO_COLOR` environment variable no longer disables styled output, per the no-color.org spec
|
|
23
|
+
* FIXED: Styled output is disabled when the `TERM` environment variable is set to `dumb`
|
|
24
|
+
* FIXED: The highline mixin decides whether to use color from its own output stream, and honors `NO_COLOR`, `FORCE_COLOR`, and `TERM=dumb`
|
|
25
|
+
* FIXED: Help text displayed through a pager honors the styled output setting, including `NO_COLOR`, `FORCE_COLOR`, and `TERM=dumb`
|
|
26
|
+
* Other fixes
|
|
27
|
+
* FIXED: Bash tab completion discards stderr from the completion command, preventing unwanted output if warnings are emitted.
|
|
28
|
+
* FIXED: Tool-not-found suggestions include namespaces
|
|
29
|
+
* FIXED: The `:push` handler creates a new array rather than appending in place, so that a frozen or non-cloneable default doesn't cause problems
|
|
30
|
+
* FIXED: Re-vendor `simple_xdg` 0.1.2 to pick up home directory fix
|
|
31
|
+
* FIXED: Re-vendor `git_cache` 0.2.0 to report an unwritable cache directory clearly and fix repo lock races
|
|
32
|
+
|
|
3
33
|
### v0.24.0 / 2026-09-11
|
|
4
34
|
|
|
5
35
|
* Feature: The `toys do` builtin provides an `--on-missing-gem` flag that governs how the `--gem` flag handles gems that are not installed.
|
data/README.md
CHANGED
|
@@ -108,9 +108,10 @@ Toys searches up the directory hierarchy for Toys files. So it will find this
|
|
|
108
108
|
also read multiple files if it finds them, so you can "scope" your tools more
|
|
109
109
|
specifically or generally by locating them in your directory hierarchy.
|
|
110
110
|
|
|
111
|
-
If you want to define "global" tools that apply anywhere, write a Toys file
|
|
112
|
-
|
|
113
|
-
(usually
|
|
111
|
+
If you want to define "global" tools that apply anywhere, write a Toys file in
|
|
112
|
+
your home directory, or put tool files in the `toys` directory under your user
|
|
113
|
+
configuration directory (usually `~/.config/toys`) or the system configuration
|
|
114
|
+
directory (usually `/etc/xdg/toys`). Toys searches these locations by default.
|
|
114
115
|
|
|
115
116
|
### A more sophisticated example
|
|
116
117
|
|
data/bin/toys
CHANGED
|
@@ -8,4 +8,11 @@ $LOAD_PATH.delete(::ENV["TOYS_LIB_PATH"])
|
|
|
8
8
|
$LOAD_PATH.unshift(::ENV["TOYS_LIB_PATH"])
|
|
9
9
|
require "toys"
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
begin
|
|
12
|
+
cli = ::Toys::StandardCLI.new
|
|
13
|
+
rescue ::Toys::StandardCLI::InvalidGlobalSourcesError => e
|
|
14
|
+
# Not Kernel#warn, which -W0 would silence, hiding why toys exited.
|
|
15
|
+
$stderr.puts(e.message) # rubocop:disable Style/StderrPuts
|
|
16
|
+
exit(2)
|
|
17
|
+
end
|
|
18
|
+
exit(cli.run(::ARGV))
|
data/core-docs/toys/cli.rb
CHANGED
|
@@ -85,6 +85,8 @@ module Toys
|
|
|
85
85
|
# as an argument, and returns a `Logger` to use when running that tool.
|
|
86
86
|
# Optional. If not provided (and no global logger is set),
|
|
87
87
|
# {Toys::CLI.default_logger_factory} is called to get a basic default.
|
|
88
|
+
# See {Toys::Runner} for how a logger can receive the verbosity of
|
|
89
|
+
# the run.
|
|
88
90
|
# @param base_level [Integer] The logger level that should correspond
|
|
89
91
|
# to zero verbosity.
|
|
90
92
|
# Optional. If not provided, defaults to the level the logger has
|
|
@@ -314,8 +316,8 @@ module Toys
|
|
|
314
316
|
# source list. If the given search directory path does not exist or does
|
|
315
317
|
# not contain either the file or directory, nothing is added.
|
|
316
318
|
#
|
|
317
|
-
# The main Toys executable uses this method to load tools from
|
|
318
|
-
# in the
|
|
319
|
+
# The main Toys executable uses this method to load tools from the
|
|
320
|
+
# directories in its upward walk and from the home directory.
|
|
319
321
|
#
|
|
320
322
|
# @param search_path [String,Pathname] A directory path to search for the
|
|
321
323
|
# well-known source file and directory. Must be a String or a Pathname.
|
|
@@ -349,9 +351,6 @@ module Toys
|
|
|
349
351
|
# given directory and works up through parent directories until it reaches
|
|
350
352
|
# the file system root or it encounters one of the "terminate" directories.
|
|
351
353
|
#
|
|
352
|
-
# The main Toys executable uses this method to load tools from the current
|
|
353
|
-
# directory and its ancestors.
|
|
354
|
-
#
|
|
355
354
|
# @param start [String,Pathname,nil] The first directory path to search.
|
|
356
355
|
# If not given, defaults to the current working directory. If provided,
|
|
357
356
|
# must be a String or a Pathname. Paths should generally be absolute.
|
data/core-docs/toys/core.rb
CHANGED
data/core-docs/toys/flag.rb
CHANGED
|
@@ -264,10 +264,12 @@ module Toys
|
|
|
264
264
|
SET_HANDLER = proc { |val| val }
|
|
265
265
|
|
|
266
266
|
##
|
|
267
|
-
# The push handler
|
|
267
|
+
# The push handler appends the given value, returning a new array. The
|
|
268
|
+
# previous array is not modified, so a shared or frozen default array
|
|
269
|
+
# can be used safely.
|
|
268
270
|
# @return [Proc]
|
|
269
271
|
#
|
|
270
|
-
PUSH_HANDLER = proc { |val, prev| prev.nil? ? [val] : prev
|
|
272
|
+
PUSH_HANDLER = proc { |val, prev| prev.nil? ? [val] : prev + [val] }
|
|
271
273
|
|
|
272
274
|
##
|
|
273
275
|
# The default handler is the set handler, which replaces the previous value.
|
data/core-docs/toys/runner.rb
CHANGED
|
@@ -34,6 +34,15 @@ module Toys
|
|
|
34
34
|
# end
|
|
35
35
|
# end
|
|
36
36
|
#
|
|
37
|
+
# While a tool runs, the Runner sets the level of the tool's logger to reflect
|
|
38
|
+
# the verbosity, as described under the `base_level` parameter of
|
|
39
|
+
# {#initialize}. A logger can also receive the verbosity itself, by
|
|
40
|
+
# implementing a `verbosity` attribute: if the logger responds to both
|
|
41
|
+
# `verbosity` and `verbosity=`, the Runner sets it to the verbosity (an
|
|
42
|
+
# Integer) for the duration of the run, and restores the previous value
|
|
43
|
+
# afterward. This lets a logger vary its behavior, such as its formatting, by
|
|
44
|
+
# verbosity independently of its level.
|
|
45
|
+
#
|
|
37
46
|
# **_Defined in the toys-core gem_**
|
|
38
47
|
#
|
|
39
48
|
class Runner
|
|
@@ -72,7 +81,8 @@ module Toys
|
|
|
72
81
|
# @param logger_factory [Proc,nil] A proc that takes a
|
|
73
82
|
# {Toys::ToolDefinition} as an argument, and returns a logger to use
|
|
74
83
|
# when running that tool. If not given,
|
|
75
|
-
# {Toys::Runner::DEFAULT_LOGGER_FACTORY} is used.
|
|
84
|
+
# {Toys::Runner::DEFAULT_LOGGER_FACTORY} is used. See {Toys::Runner}
|
|
85
|
+
# for how a logger can receive the verbosity of the run.
|
|
76
86
|
# @param base_level [Integer,nil] The logger level that corresponds to zero
|
|
77
87
|
# verbosity. If not provided, the level the logger has before a run
|
|
78
88
|
# adjusts it is used (typically Logger::WARN). A run nested inside
|
|
@@ -22,8 +22,9 @@ module Toys
|
|
|
22
22
|
# occurs. Default is {USAGE_ERROR_EXIT_CODE}.
|
|
23
23
|
# @param stream [IO] Output stream to write to. Default is stderr.
|
|
24
24
|
# @param styled_output [boolean,nil] Cause the tool to display help text
|
|
25
|
-
# with ansi styles. If `nil`, display styles
|
|
26
|
-
#
|
|
25
|
+
# with ansi styles. If `nil`, whether to display styles is inferred
|
|
26
|
+
# from the output stream and the environment. See
|
|
27
|
+
# {Toys::Utils::Terminal.infer_styled}. Default is `nil`.
|
|
27
28
|
#
|
|
28
29
|
def initialize(exit_code: nil, stream: $stderr, styled_output: nil)
|
|
29
30
|
# Source available in the toys-core gem
|
|
@@ -17,7 +17,7 @@ module Toys
|
|
|
17
17
|
# Default help flags
|
|
18
18
|
# @return [Array<String>]
|
|
19
19
|
#
|
|
20
|
-
DEFAULT_HELP_FLAGS = ["-?", "--help"].freeze
|
|
20
|
+
DEFAULT_HELP_FLAGS = ["-h", "-?", "--help"].freeze
|
|
21
21
|
|
|
22
22
|
##
|
|
23
23
|
# Default usage flags
|
|
@@ -165,8 +165,9 @@ module Toys
|
|
|
165
165
|
# false) if the output stream is not a tty.
|
|
166
166
|
# @param stream [IO] Output stream to write to. Default is stdout.
|
|
167
167
|
# @param styled_output [boolean,nil] Cause the tool to display help text
|
|
168
|
-
# with ansi styles. If `nil`, display styles
|
|
169
|
-
#
|
|
168
|
+
# with ansi styles. If `nil`, whether to display styles is inferred
|
|
169
|
+
# from the output stream and the environment. See
|
|
170
|
+
# {Toys::Utils::Terminal.infer_styled}. Default is `nil`.
|
|
170
171
|
#
|
|
171
172
|
def initialize(help_flags: false,
|
|
172
173
|
usage_flags: false,
|
|
@@ -25,6 +25,11 @@ module Toys
|
|
|
25
25
|
# The arguments will be passed on to the
|
|
26
26
|
# [HighLine constructor](https://www.rubydoc.info/gems/highline/HighLine:initialize).
|
|
27
27
|
#
|
|
28
|
+
# Whether the HighLine object uses color is inferred from its output
|
|
29
|
+
# stream and the environment, using the same rule as a terminal. See
|
|
30
|
+
# {Toys::Utils::Terminal.infer_styled}. You can override it by setting
|
|
31
|
+
# `use_color` on the HighLine object.
|
|
32
|
+
#
|
|
28
33
|
# **_Defined in the toys-core gem_**
|
|
29
34
|
#
|
|
30
35
|
module Highline
|
|
@@ -16,7 +16,9 @@ module Toys
|
|
|
16
16
|
# Access a git cache.
|
|
17
17
|
#
|
|
18
18
|
# @param cache_dir [String] The path to the cache directory. Defaults to
|
|
19
|
-
# a specific directory in the user's XDG cache.
|
|
19
|
+
# a specific directory in the user's XDG cache. Cache data is stored
|
|
20
|
+
# in a subdirectory named for the cache format version, so that clients
|
|
21
|
+
# using incompatible formats can share a cache directory safely.
|
|
20
22
|
#
|
|
21
23
|
def initialize(cache_dir: nil)
|
|
22
24
|
# Source available in the toys-core gem
|
|
@@ -98,8 +100,9 @@ module Toys
|
|
|
98
100
|
# repositories are requested, they will be reloaded from the remote
|
|
99
101
|
# repository from scratch.
|
|
100
102
|
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
+
# This waits for any in-progress {#get} calls for these repos to finish.
|
|
104
|
+
# However, be careful not to remove repos whose shared sources are
|
|
105
|
+
# currently in use by other Toys::Utils::GitCache clients.
|
|
103
106
|
#
|
|
104
107
|
# @param remotes [Array<String>,:all,nil] The remotes to remove. If set
|
|
105
108
|
# to :all or nil, removes all repos.
|
|
@@ -30,14 +30,18 @@ module Toys
|
|
|
30
30
|
# stream. Default is `true`.
|
|
31
31
|
# @param exec_service [Toys::Utils::Exec] The service to use for
|
|
32
32
|
# executing commands, or `nil` (the default) to use a default.
|
|
33
|
+
# @param output [IO,StringIO,nil] The stream to which the pager process
|
|
34
|
+
# writes its output, and the default fallback stream. If `nil` (the
|
|
35
|
+
# default), the pager process inherits the parent's standard output.
|
|
33
36
|
# @param fallback_io [IO] An IO-like object to write to if the pager is
|
|
34
|
-
# disabled. Defaults to
|
|
37
|
+
# disabled or could not be executed. Defaults to the `output` stream
|
|
38
|
+
# if one is given, otherwise `$stdout`.
|
|
35
39
|
# @param rescue_broken_pipes [boolean] If `true` (the default), broken
|
|
36
40
|
# pipes are silently rescued. This prevents the exception from
|
|
37
41
|
# propagating out if the pager is interrupted. Set this parameter to
|
|
38
42
|
# `false` to disable this behavior.
|
|
39
43
|
#
|
|
40
|
-
def initialize(command: true, exec_service: nil, fallback_io: nil,
|
|
44
|
+
def initialize(command: true, exec_service: nil, output: nil, fallback_io: nil,
|
|
41
45
|
rescue_broken_pipes: true)
|
|
42
46
|
# Source available in the toys-core gem
|
|
43
47
|
end
|
|
@@ -71,12 +75,32 @@ module Toys
|
|
|
71
75
|
#
|
|
72
76
|
attr_accessor :command
|
|
73
77
|
|
|
78
|
+
##
|
|
79
|
+
# The stream to which the pager process writes its output, or `nil` if
|
|
80
|
+
# the pager process inherits the parent's standard output.
|
|
81
|
+
#
|
|
82
|
+
# @return [IO,StringIO,nil]
|
|
83
|
+
#
|
|
84
|
+
attr_accessor :output
|
|
85
|
+
|
|
74
86
|
##
|
|
75
87
|
# The IO stream used if the pager is disabled or could not be executed.
|
|
88
|
+
# If not set explicitly, this is the {#output} stream if one is set,
|
|
89
|
+
# otherwise `$stdout`.
|
|
76
90
|
#
|
|
77
91
|
# @return [IO]
|
|
78
92
|
#
|
|
79
|
-
|
|
93
|
+
def fallback_io
|
|
94
|
+
# Source available in the toys-core gem
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
##
|
|
98
|
+
# Set the IO stream used if the pager is disabled or could not be
|
|
99
|
+
# executed. Set to `nil` to use the default.
|
|
100
|
+
#
|
|
101
|
+
# @param value [IO,nil]
|
|
102
|
+
#
|
|
103
|
+
attr_writer :fallback_io
|
|
80
104
|
|
|
81
105
|
class << self
|
|
82
106
|
##
|
|
@@ -91,8 +115,12 @@ module Toys
|
|
|
91
115
|
# stream. Default is `true`.
|
|
92
116
|
# @param exec_service [Toys::Utils::Exec] The service to use for
|
|
93
117
|
# executing commands, or `nil` (the default) to use a default.
|
|
118
|
+
# @param output [IO,StringIO,nil] The stream to which the pager process
|
|
119
|
+
# writes its output, and the default fallback stream. If `nil` (the
|
|
120
|
+
# default), the pager process inherits the parent's standard output.
|
|
94
121
|
# @param fallback_io [IO] An IO-like object to write to if the pager is
|
|
95
|
-
# disabled. Defaults to
|
|
122
|
+
# disabled or could not be executed. Defaults to the `output` stream
|
|
123
|
+
# if one is given, otherwise `$stdout`.
|
|
96
124
|
# @param rescue_broken_pipes [boolean] If `true` (the default), broken
|
|
97
125
|
# pipes are silently rescued. This prevents the exception from
|
|
98
126
|
# propagating out if the pager is interrupted. Set this parameter to
|
|
@@ -107,6 +135,7 @@ module Toys
|
|
|
107
135
|
#
|
|
108
136
|
def start(command: true,
|
|
109
137
|
exec_service: nil,
|
|
138
|
+
output: nil,
|
|
110
139
|
fallback_io: nil,
|
|
111
140
|
rescue_broken_pipes: true,
|
|
112
141
|
&block)
|
|
@@ -16,6 +16,32 @@ module Toys
|
|
|
16
16
|
# **_Defined in the toys-core gem_**
|
|
17
17
|
#
|
|
18
18
|
class StandardUI
|
|
19
|
+
##
|
|
20
|
+
# The logger class created by {StandardUI#create_logger}. It is a
|
|
21
|
+
# standard `Logger` that also has a `verbosity` attribute, which the
|
|
22
|
+
# {Toys::Runner} sets to the verbosity of the run, as described in
|
|
23
|
+
# {Toys::Runner}. The formatter installed by {StandardUI#create_logger}
|
|
24
|
+
# uses it to choose a format.
|
|
25
|
+
#
|
|
26
|
+
# **_Defined in the toys-core gem_**
|
|
27
|
+
#
|
|
28
|
+
class VerbosityLogger < ::Logger
|
|
29
|
+
##
|
|
30
|
+
# Create a logger. Takes the same arguments as the standard `Logger`.
|
|
31
|
+
# The verbosity is initially zero.
|
|
32
|
+
#
|
|
33
|
+
def initialize(*args, **kwargs)
|
|
34
|
+
# Source available in the toys-core gem
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# The verbosity of the current run, or zero if not running.
|
|
39
|
+
#
|
|
40
|
+
# @return [Integer]
|
|
41
|
+
#
|
|
42
|
+
attr_accessor :verbosity
|
|
43
|
+
end
|
|
44
|
+
|
|
19
45
|
##
|
|
20
46
|
# Create a Standard UI.
|
|
21
47
|
#
|
|
@@ -114,10 +140,17 @@ module Toys
|
|
|
114
140
|
# specification in {Toys::Runner}, this must take a {Toys::ToolDefinition}
|
|
115
141
|
# as an argument, and return a `Logger`.
|
|
116
142
|
#
|
|
117
|
-
# The base implementation returns a
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
143
|
+
# The base implementation returns a
|
|
144
|
+
# {Toys::Utils::StandardUI::VerbosityLogger}, which receives the
|
|
145
|
+
# verbosity of the run from the {Toys::Runner}. The logger writes to the
|
|
146
|
+
# UI's terminal. It formats each entry using {#format_verbose_log_entry}
|
|
147
|
+
# if {#verbose_log_format?} returns true for the verbosity, or
|
|
148
|
+
# {#format_simple_log_entry} otherwise. It sets the level to
|
|
149
|
+
# `Logger::WARN` by default. Either this method or the helper methods can
|
|
150
|
+
# be overridden to change this behavior.
|
|
151
|
+
#
|
|
152
|
+
# If {#format_log_entry} is overridden, however, the override formats
|
|
153
|
+
# every entry regardless of verbosity. That behavior is deprecated.
|
|
121
154
|
#
|
|
122
155
|
# @param _tool {Toys::ToolDefinition} The tool definition of the tool to
|
|
123
156
|
# be executed
|
|
@@ -175,10 +208,54 @@ module Toys
|
|
|
175
208
|
# Source available in the toys-core gem
|
|
176
209
|
end
|
|
177
210
|
|
|
211
|
+
##
|
|
212
|
+
# Determines whether loggers created by this UI's logger factory use
|
|
213
|
+
# the verbose format, {#format_verbose_log_entry}, rather than the simple
|
|
214
|
+
# format, {#format_simple_log_entry}, for the given verbosity.
|
|
215
|
+
#
|
|
216
|
+
# The base implementation returns true if the verbosity is positive. This
|
|
217
|
+
# method can be overridden to change the behavior of loggers created by
|
|
218
|
+
# this UI.
|
|
219
|
+
#
|
|
220
|
+
# @param verbosity [Integer] The verbosity of the run.
|
|
221
|
+
# @return [boolean]
|
|
222
|
+
#
|
|
223
|
+
def verbose_log_format?(verbosity)
|
|
224
|
+
# Source available in the toys-core gem
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
##
|
|
228
|
+
# Implementation of the formatter used by loggers created by this UI's
|
|
229
|
+
# logger factory when the simple format is in effect. This interface is
|
|
230
|
+
# defined by the standard `Logger` class.
|
|
231
|
+
#
|
|
232
|
+
# The base implementation prefixes the first line of the message with the
|
|
233
|
+
# severity, styled using {#log_header_severity_styles}. If the message is
|
|
234
|
+
# an exception, it includes the exception message and class, but omits
|
|
235
|
+
# the backtrace.
|
|
236
|
+
#
|
|
237
|
+
# This method can be overridden to change the behavior of loggers created
|
|
238
|
+
# by this UI.
|
|
239
|
+
#
|
|
240
|
+
# @param severity [String]
|
|
241
|
+
# @param _time [Time]
|
|
242
|
+
# @param _progname [String]
|
|
243
|
+
# @param msg [Object]
|
|
244
|
+
# @return [String]
|
|
245
|
+
#
|
|
246
|
+
def format_simple_log_entry(severity, _time, _progname, msg)
|
|
247
|
+
# Source available in the toys-core gem
|
|
248
|
+
end
|
|
249
|
+
|
|
178
250
|
##
|
|
179
251
|
# Implementation of the formatter used by loggers created by this UI's
|
|
180
|
-
# logger factory
|
|
181
|
-
# class.
|
|
252
|
+
# logger factory when the verbose format is in effect. This interface is
|
|
253
|
+
# defined by the standard `Logger` class.
|
|
254
|
+
#
|
|
255
|
+
# The base implementation prefixes the message with a header containing
|
|
256
|
+
# the timestamp and severity, styled using {#log_header_severity_styles}.
|
|
257
|
+
# If the message is an exception, it includes the exception message and
|
|
258
|
+
# class, followed by the backtrace.
|
|
182
259
|
#
|
|
183
260
|
# This method can be overridden to change the behavior of loggers created
|
|
184
261
|
# by this UI.
|
|
@@ -189,7 +266,32 @@ module Toys
|
|
|
189
266
|
# @param msg [Object]
|
|
190
267
|
# @return [String]
|
|
191
268
|
#
|
|
192
|
-
def
|
|
269
|
+
def format_verbose_log_entry(severity, time, _progname, msg)
|
|
270
|
+
# Source available in the toys-core gem
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
##
|
|
274
|
+
# A legacy formatter for loggers created by this UI's logger factory.
|
|
275
|
+
# This interface is defined by the standard `Logger` class.
|
|
276
|
+
#
|
|
277
|
+
# The base implementation calls {#format_verbose_log_entry}, and is not
|
|
278
|
+
# used by loggers created by this UI's logger factory unless it is
|
|
279
|
+
# overridden. If a subclass overrides this method, the override is used
|
|
280
|
+
# to format every entry regardless of verbosity, and
|
|
281
|
+
# {#verbose_log_format?}, {#format_verbose_log_entry}, and
|
|
282
|
+
# {#format_simple_log_entry} are not called by the logger. The override
|
|
283
|
+
# may call `super` to get the verbose format.
|
|
284
|
+
#
|
|
285
|
+
# @deprecated Override {#format_simple_log_entry} and
|
|
286
|
+
# {#format_verbose_log_entry} instead.
|
|
287
|
+
#
|
|
288
|
+
# @param severity [String]
|
|
289
|
+
# @param time [Time]
|
|
290
|
+
# @param progname [String]
|
|
291
|
+
# @param msg [Object]
|
|
292
|
+
# @return [String]
|
|
293
|
+
#
|
|
294
|
+
def format_log_entry(severity, time, progname, msg)
|
|
193
295
|
# Source available in the toys-core gem
|
|
194
296
|
end
|
|
195
297
|
end
|
|
@@ -106,13 +106,55 @@ module Toys
|
|
|
106
106
|
# Source available in the toys-core gem
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
+
##
|
|
110
|
+
# Infers whether styled output should be written to the given output,
|
|
111
|
+
# from the output itself and the environment. This is the rule a
|
|
112
|
+
# terminal uses when it is not told explicitly whether to style output,
|
|
113
|
+
# and it is available to tools that write styled output by other means.
|
|
114
|
+
#
|
|
115
|
+
# The following checks are applied in order, and the first that applies
|
|
116
|
+
# decides the result:
|
|
117
|
+
#
|
|
118
|
+
# 1. If the `FORCE_COLOR` environment variable is set to `0` or `false`
|
|
119
|
+
# (in any case), output is not styled. This follows Node.js and the
|
|
120
|
+
# chalk library, which are the most common consumers of
|
|
121
|
+
# `FORCE_COLOR`, rather than the
|
|
122
|
+
# [force-color.org](https://force-color.org) standard, which would
|
|
123
|
+
# force styling on for these values.
|
|
124
|
+
# 2. If the `FORCE_COLOR` environment variable is set to any other
|
|
125
|
+
# nonempty value, output is styled. Following the force-color.org
|
|
126
|
+
# standard, this overrides `NO_COLOR`, so that color can be forced
|
|
127
|
+
# for one run even when `NO_COLOR` is set as a general preference.
|
|
128
|
+
# An empty `FORCE_COLOR` is treated as if it were unset, also
|
|
129
|
+
# following the force-color.org standard.
|
|
130
|
+
# 3. If the `NO_COLOR` environment variable is set to a nonempty value,
|
|
131
|
+
# output is not styled, following the
|
|
132
|
+
# [no-color.org](https://no-color.org) standard.
|
|
133
|
+
# 4. If the `TERM` environment variable is set to `dumb`, output is not
|
|
134
|
+
# styled.
|
|
135
|
+
# 5. Otherwise, output is styled if the output is a tty.
|
|
136
|
+
#
|
|
137
|
+
# Note that all styling is affected, not only color. Also note that an
|
|
138
|
+
# explicit choice, such as passing `styled: true` or `styled: false` to
|
|
139
|
+
# {Terminal#initialize}, takes precedence over all of these checks,
|
|
140
|
+
# because this method is then not called at all.
|
|
141
|
+
#
|
|
142
|
+
# @param output [IO,Logger,nil] The output stream.
|
|
143
|
+
# @param env [Hash{String=>String}] The environment. Defaults to `ENV`.
|
|
144
|
+
# @return [boolean] Whether output should be styled.
|
|
145
|
+
#
|
|
146
|
+
def self.infer_styled(output, env: ::ENV)
|
|
147
|
+
# Source available in the toys-core gem
|
|
148
|
+
end
|
|
149
|
+
|
|
109
150
|
##
|
|
110
151
|
# Create a terminal.
|
|
111
152
|
#
|
|
112
153
|
# @param input [IO,nil] Input stream.
|
|
113
154
|
# @param output [IO,Logger,nil] Output stream or logger.
|
|
114
155
|
# @param styled [boolean,nil] Whether to output ansi styles. If `nil`, the
|
|
115
|
-
# setting is inferred from
|
|
156
|
+
# setting is inferred from the output and the environment. See
|
|
157
|
+
# {Terminal.infer_styled}.
|
|
116
158
|
#
|
|
117
159
|
def initialize(input: $stdin, output: $stdout, styled: nil)
|
|
118
160
|
# Source available in the toys-core gem
|
data/core-docs/toys/utils/xdg.rb
CHANGED
|
@@ -63,6 +63,12 @@ module Toys
|
|
|
63
63
|
##
|
|
64
64
|
# Returns the absolute path to the current user's home directory.
|
|
65
65
|
#
|
|
66
|
+
# Uses the value of the `$HOME` environment variable if it is an absolute
|
|
67
|
+
# path, otherwise falls back to the system's notion of the home directory.
|
|
68
|
+
# If no home directory can be determined (for example, when `$HOME` is
|
|
69
|
+
# unset and the current user has no passwd entry, as can happen in a
|
|
70
|
+
# container run under an arbitrary UID), returns the filesystem root `"/"`.
|
|
71
|
+
#
|
|
66
72
|
# @return [String]
|
|
67
73
|
#
|
|
68
74
|
def home_dir
|
|
@@ -359,7 +365,7 @@ module Toys
|
|
|
359
365
|
# Version of the simple_xdg gem
|
|
360
366
|
# @return [String]
|
|
361
367
|
#
|
|
362
|
-
VERSION = "0.1.
|
|
368
|
+
VERSION = "0.1.2"
|
|
363
369
|
end
|
|
364
370
|
end
|
|
365
371
|
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module Toys
|
|
2
|
+
##
|
|
3
|
+
# A warning reporter that supports throttling of repeated messages and
|
|
4
|
+
# environment variable based silencing. Used in particular to display
|
|
5
|
+
# deprecation warnings.
|
|
6
|
+
#
|
|
7
|
+
# **_Defined in the toys-core gem_**
|
|
8
|
+
#
|
|
9
|
+
module Warnings
|
|
10
|
+
##
|
|
11
|
+
# @return [Integer] The default value for {Warnings.max_count}.
|
|
12
|
+
#
|
|
13
|
+
DEFAULT_MAX_COUNT = 5
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# @return [String] The name of an environment variable that, when set to a
|
|
17
|
+
# non-empty value, suppresses warnings emitted by this module.
|
|
18
|
+
#
|
|
19
|
+
SUPPRESS_WARNINGS_ENV = "TOYS_SUPPRESS_WARNINGS"
|
|
20
|
+
|
|
21
|
+
FURTHER_SUPPRESSED_MSG = "further warnings suppressed"
|
|
22
|
+
private_constant :FURTHER_SUPPRESSED_MSG
|
|
23
|
+
|
|
24
|
+
ENV_SUPPRESSION_MSG = "to suppress these warnings altogether, set #{SUPPRESS_WARNINGS_ENV} to a nonempty value"
|
|
25
|
+
private_constant :ENV_SUPPRESSION_MSG
|
|
26
|
+
|
|
27
|
+
@mutex = ::Mutex.new
|
|
28
|
+
@max_count = DEFAULT_MAX_COUNT
|
|
29
|
+
|
|
30
|
+
class << self
|
|
31
|
+
##
|
|
32
|
+
# The maximum number of times a warning with the same identity will be
|
|
33
|
+
# displayed before further instances are suppressed, or nil to keep
|
|
34
|
+
# displaying each warning regardless of how many times it has repeated.
|
|
35
|
+
# Defaults to {DEFAULT_MAX_COUNT}. Can be set using
|
|
36
|
+
# {Toys::Warnings.max_count=}.
|
|
37
|
+
#
|
|
38
|
+
# @return [Integer,nil]
|
|
39
|
+
#
|
|
40
|
+
attr_reader :max_count
|
|
41
|
+
|
|
42
|
+
##
|
|
43
|
+
# Set the maximum number of times a warning with the same identity will
|
|
44
|
+
# be displayed before further instances are suppressed. Must be a
|
|
45
|
+
# nonnegative integer, or nil to keep displaying each warning regardless
|
|
46
|
+
# of how many times it has repeated. The value 0 suppresses warnings
|
|
47
|
+
# unconditionally.
|
|
48
|
+
#
|
|
49
|
+
# @param value [Integer,nil] The new max_count value
|
|
50
|
+
#
|
|
51
|
+
def max_count=(value)
|
|
52
|
+
# Source available in the toys-core gem
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
##
|
|
56
|
+
# Displays a warning message.
|
|
57
|
+
#
|
|
58
|
+
# You must pass an identifier object and a message string. The identifier
|
|
59
|
+
# should identify "which" warning is being displayed, and is used to
|
|
60
|
+
# count repeated warnings so they can be throttled after a certain number
|
|
61
|
+
# of instances.
|
|
62
|
+
#
|
|
63
|
+
# Uses the Ruby `Kernel#warn` method, so it is affected by `$VERBOSE` and
|
|
64
|
+
# the `-W0` flag. Does not currently support the `category:` argument to
|
|
65
|
+
# `Kernel#warn` because it is not supported in Ruby 2.7, and in newer
|
|
66
|
+
# Rubies, common values such as `category: :deprecated` default to silent,
|
|
67
|
+
# whereas this method should not be silent unless explicitly requested.
|
|
68
|
+
#
|
|
69
|
+
# @param identifier [Object] An object that identifies the warning for
|
|
70
|
+
# counting purposes. Generally this should be a fixed small set of
|
|
71
|
+
# objects, preferably symbols, as each identifier seen is used as a
|
|
72
|
+
# hash key and never deleted.
|
|
73
|
+
# @param message [String] The warning message
|
|
74
|
+
# @param uplevel [Integer,nil] If given and set to a nonnegative Integer,
|
|
75
|
+
# the warning will be prepended with the caller frame, that many
|
|
76
|
+
# stack levels above the call site. If not given or set to nil, the
|
|
77
|
+
# caller is not included in the report.
|
|
78
|
+
# @param max_count [Integer,nil,:default] The maximum number of times a
|
|
79
|
+
# warning with the same identity will be displayed before further
|
|
80
|
+
# instances are suppressed. Must be a nonnegative integer, or nil to
|
|
81
|
+
# keep displaying each warning regardless of how many times it has
|
|
82
|
+
# repeated. The value 0 suppresses warnings of this identifier
|
|
83
|
+
# unconditionally. The special value `:default` (which is used if the
|
|
84
|
+
# argument is not provided) falls back to {Toys::Warnings.max_count}.
|
|
85
|
+
#
|
|
86
|
+
# @return [Integer] The number of times this warning's identifier has
|
|
87
|
+
# happened, regardless of whether it was actually displayed.
|
|
88
|
+
#
|
|
89
|
+
def warn(identifier, message, uplevel: nil, max_count: :default)
|
|
90
|
+
# Source available in the toys-core gem
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
reset_counts
|
|
95
|
+
end
|
|
96
|
+
end
|
data/core-docs/toys-core.rb
CHANGED
|
@@ -53,7 +53,8 @@
|
|
|
53
53
|
# {Toys::Middleware}, which are resolved by name through
|
|
54
54
|
# {Toys::ModuleLookup}, as well as {Toys::WrappableString},
|
|
55
55
|
# {Toys::ToolNameSplitter} which interprets delimiters in tool names, the
|
|
56
|
-
# named sentinel {Toys::UniqueKey},
|
|
56
|
+
# named sentinel {Toys::UniqueKey}, the warning reporter {Toys::Warnings},
|
|
57
|
+
# and the error classes.
|
|
57
58
|
#
|
|
58
59
|
# The deliberate upward dependencies are:
|
|
59
60
|
#
|
data/docs/guide.md
CHANGED
|
@@ -233,7 +233,7 @@ However, Toys adds a few standard flags globally to every tool. (It is possible
|
|
|
233
233
|
for individual tools to override these flags, but most tools should support
|
|
234
234
|
them.) These standard flags include:
|
|
235
235
|
|
|
236
|
-
* `--help` (also `-?`) which displays the full help screen for the tool.
|
|
236
|
+
* `--help` (also `-h` or `-?`) which displays the full help screen for the tool.
|
|
237
237
|
* `--usage` which displays a shorter usage screen for the tool.
|
|
238
238
|
* `--verbose` (also `-v`) which increases the verbosity. This affects the
|
|
239
239
|
tool's logging display, increasing the number of log levels shown. This
|
|
@@ -1461,6 +1461,19 @@ tool file the error occurred, but doesn't give you the entire stack trace
|
|
|
1461
1461
|
(which could include a number of frames internal to the Toys framework). If you
|
|
1462
1462
|
want to see the full stack trace, set the `TOYS_TRACE` environment variable.
|
|
1463
1463
|
|
|
1464
|
+
### Warnings
|
|
1465
|
+
|
|
1466
|
+
Toys may display warnings on the standard error stream, for example when a
|
|
1467
|
+
tool uses a feature of Toys that has been deprecated. These warnings are
|
|
1468
|
+
separate from the logger described above, and are not affected by verbosity
|
|
1469
|
+
or by the `--quiet` flag. If the same warning is triggered repeatedly during a
|
|
1470
|
+
single run, Toys displays only the first few instances.
|
|
1471
|
+
|
|
1472
|
+
To suppress these warnings entirely, set the `TOYS_SUPPRESS_WARNINGS`
|
|
1473
|
+
environment variable to a nonempty value. Because Toys uses Ruby's standard
|
|
1474
|
+
`Kernel#warn` mechanism to display them, they are also silenced if Ruby
|
|
1475
|
+
warnings are disabled, for example by running Ruby with the `-W0` flag.
|
|
1476
|
+
|
|
1464
1477
|
### Running tools from tools
|
|
1465
1478
|
|
|
1466
1479
|
A common operation a tool might want to do is "call" another tool. This can be
|
|
@@ -1723,12 +1736,26 @@ When Toys runs, it looks for tools in a **search path**. Specifically:
|
|
|
1723
1736
|
working directory*.
|
|
1724
1737
|
2. It does the same in the *parent directory* of the current directory, and
|
|
1725
1738
|
then its parent, and so on until it hits either the root of the file system
|
|
1726
|
-
or
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1739
|
+
or the current user's *home directory*. The home directory itself is not
|
|
1740
|
+
part of this step.
|
|
1741
|
+
3. It looks in a list of *global sources*:
|
|
1742
|
+
* A `.toys.rb` file and/or a `.toys` directory in the current user's
|
|
1743
|
+
home directory.
|
|
1744
|
+
* The `toys` directory under the user configuration directory given by
|
|
1745
|
+
the `XDG_CONFIG_HOME` environment variable (`~/.config/toys` by
|
|
1746
|
+
default).
|
|
1747
|
+
* The `toys` directory under each system configuration directory given by
|
|
1748
|
+
the colon-delimited `XDG_CONFIG_DIRS` environment variable
|
|
1749
|
+
(`/etc/xdg/toys` by default), in order.
|
|
1750
|
+
|
|
1751
|
+
Unlike `.toys` directories, the `toys` directories under the configuration
|
|
1752
|
+
directories are not tied to any project directory, so tools loaded from
|
|
1753
|
+
them have no
|
|
1754
|
+
[context directory](#working-directory-and-context-directory) by default.
|
|
1755
|
+
|
|
1756
|
+
Toys does *not* search parents of global sources. If the current working
|
|
1757
|
+
directory is inside one of the `toys` configuration directories, Toys
|
|
1758
|
+
skips steps (1) and (2) and loads only the global sources.
|
|
1732
1759
|
|
|
1733
1760
|
It uses the *first* implementation that it finds for the requested tool. For
|
|
1734
1761
|
example, if the tool `greet` is defined in the `.toys.rb` file in the current
|
|
@@ -1756,6 +1783,15 @@ That is, they may be different depending on what directory you are in. However,
|
|
|
1756
1783
|
step (3) is *not* context-dependent, and is searched regardless of where you
|
|
1757
1784
|
are located. Tools defined here are *global*, available everywhere.
|
|
1758
1785
|
|
|
1786
|
+
You can choose which global sources are searched by setting the
|
|
1787
|
+
`TOYS_GLOBAL_SOURCES` environment variable. The global sources form three
|
|
1788
|
+
groups: `home` (the home directory), `user` (the user configuration directory),
|
|
1789
|
+
and `site` (the system configuration directories). Set the variable to a
|
|
1790
|
+
comma-delimited list of the groups to search, in that order. For example,
|
|
1791
|
+
`TOYS_GLOBAL_SOURCES=user,site` omits the home directory. Set it to `none` to
|
|
1792
|
+
search no global sources, which can be useful for reproducible runs in CI. If
|
|
1793
|
+
the variable is unset or empty, all three groups are searched.
|
|
1794
|
+
|
|
1759
1795
|
#### Stopping search
|
|
1760
1796
|
|
|
1761
1797
|
Though it is uncommon practice, it is possible to stop the search process and
|
data/lib/toys/standard_cli.rb
CHANGED
|
@@ -66,10 +66,27 @@ module Toys
|
|
|
66
66
|
DEFAULT_VERSION_FLAG_DESC = "Show the version of Toys."
|
|
67
67
|
|
|
68
68
|
##
|
|
69
|
-
# Name of the
|
|
69
|
+
# Name of the environment variable that selects which groups of global
|
|
70
|
+
# sources are searched.
|
|
70
71
|
# @return [String]
|
|
71
72
|
#
|
|
72
|
-
|
|
73
|
+
GLOBAL_SOURCES_ENV = "TOYS_GLOBAL_SOURCES"
|
|
74
|
+
|
|
75
|
+
##
|
|
76
|
+
# The groups of global sources, in search order. The `home` group is
|
|
77
|
+
# `$HOME/.toys.rb` and `$HOME/.toys/`, the `user` group is the `toys`
|
|
78
|
+
# tool directory under `$XDG_CONFIG_HOME`, and the `site` group is the
|
|
79
|
+
# `toys` tool directories under each of `$XDG_CONFIG_DIRS`.
|
|
80
|
+
# @return [Array<String>]
|
|
81
|
+
#
|
|
82
|
+
GLOBAL_SOURCE_GROUPS = ["home", "user", "site"].freeze
|
|
83
|
+
|
|
84
|
+
##
|
|
85
|
+
# Raised by the constructor if the `TOYS_GLOBAL_SOURCES` environment
|
|
86
|
+
# variable has an invalid value.
|
|
87
|
+
#
|
|
88
|
+
class InvalidGlobalSourcesError < ::StandardError
|
|
89
|
+
end
|
|
73
90
|
|
|
74
91
|
##
|
|
75
92
|
# Create a standard CLI, configured with the appropriate paths and
|
|
@@ -77,7 +94,8 @@ module Toys
|
|
|
77
94
|
#
|
|
78
95
|
# @param custom_paths [String,Array<String>] Custom paths to use. If set,
|
|
79
96
|
# the CLI uses only the given paths. If not, the CLI will search for
|
|
80
|
-
# paths from the current directory and global paths
|
|
97
|
+
# paths from the current directory and global paths, as selected by
|
|
98
|
+
# the `TOYS_GLOBAL_SOURCES` environment variable.
|
|
81
99
|
# @param include_builtins [boolean] Add the builtin tools. Default is true.
|
|
82
100
|
# @param cur_dir [String,nil] Starting search directory for sources.
|
|
83
101
|
# Defaults to the current working directory.
|
|
@@ -87,6 +105,8 @@ module Toys
|
|
|
87
105
|
# @param gems_util [Toys::Utils::Gems,nil] A custom Gems utility instance
|
|
88
106
|
# to use when resolving gem sources. Optional. If nil or not
|
|
89
107
|
# specified, uses a process-wide default Gems utility.
|
|
108
|
+
# @raise [InvalidGlobalSourcesError] if no custom paths are given and the
|
|
109
|
+
# `TOYS_GLOBAL_SOURCES` environment variable has an invalid value.
|
|
90
110
|
#
|
|
91
111
|
def initialize(custom_paths: nil,
|
|
92
112
|
include_builtins: true,
|
|
@@ -112,7 +132,7 @@ module Toys
|
|
|
112
132
|
if custom_paths
|
|
113
133
|
Array(custom_paths).each { |path| add_source(path) }
|
|
114
134
|
else
|
|
115
|
-
|
|
135
|
+
add_default_sources(cur_dir)
|
|
116
136
|
end
|
|
117
137
|
add_builtins if include_builtins
|
|
118
138
|
end
|
|
@@ -130,21 +150,171 @@ module Toys
|
|
|
130
150
|
end
|
|
131
151
|
|
|
132
152
|
##
|
|
133
|
-
# Add
|
|
134
|
-
# global
|
|
153
|
+
# Add the sources found by the default search: the current directory and
|
|
154
|
+
# its ancestors, followed by the selected global sources.
|
|
135
155
|
#
|
|
136
|
-
# @param cur_dir [String] The starting directory path, or nil to use
|
|
137
|
-
# current directory
|
|
156
|
+
# @param cur_dir [String,nil] The starting directory path, or nil to use
|
|
157
|
+
# the current directory
|
|
138
158
|
# @return [self]
|
|
139
159
|
#
|
|
140
|
-
def
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
160
|
+
def add_default_sources(cur_dir)
|
|
161
|
+
groups = selected_global_groups
|
|
162
|
+
warn_removed_global_paths
|
|
163
|
+
require "toys/utils/xdg"
|
|
164
|
+
xdg = Utils::XDG.new
|
|
165
|
+
home_dir = real_directory(xdg.home_dir)
|
|
166
|
+
user_dirs = [real_directory(::File.join(xdg.config_home, "toys"))].compact
|
|
167
|
+
site_dirs = xdg.config_dirs.map { |dir| real_directory(::File.join(dir, "toys")) }.compact
|
|
168
|
+
walk_dirs = upward_walk_dirs(cur_dir || ::Dir.pwd, home_dir, user_dirs + site_dirs)
|
|
169
|
+
walk_dirs.each { |dir| add_search_path(dir) }
|
|
170
|
+
warn_etc_toys_files(walk_dirs)
|
|
171
|
+
add_global_sources(groups, home_dir, user_dirs, site_dirs)
|
|
145
172
|
self
|
|
146
173
|
end
|
|
147
174
|
|
|
175
|
+
##
|
|
176
|
+
# Parse and validate the global sources environment variable.
|
|
177
|
+
#
|
|
178
|
+
# @return [Array<String>] The selected groups
|
|
179
|
+
# @raise [InvalidGlobalSourcesError] if the value is invalid
|
|
180
|
+
#
|
|
181
|
+
def selected_global_groups
|
|
182
|
+
value = ::ENV[GLOBAL_SOURCES_ENV].to_s
|
|
183
|
+
return GLOBAL_SOURCE_GROUPS if value.empty?
|
|
184
|
+
return [] if value == "none"
|
|
185
|
+
groups = value.split(",", -1)
|
|
186
|
+
return groups if GLOBAL_SOURCE_GROUPS.select { |group| groups.include?(group) } == groups
|
|
187
|
+
raise InvalidGlobalSourcesError,
|
|
188
|
+
"Invalid value for #{GLOBAL_SOURCES_ENV}: #{value.inspect}. Expected \"none\", or a" \
|
|
189
|
+
" comma-delimited list of groups from #{GLOBAL_SOURCE_GROUPS.join(',')} in that order."
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
##
|
|
193
|
+
# Add the global sources in the selected groups, skipping any directory
|
|
194
|
+
# that resolves to one already added.
|
|
195
|
+
#
|
|
196
|
+
# @param groups [Array<String>] The selected groups
|
|
197
|
+
# @param home_dir [String,nil] The real path of the home directory
|
|
198
|
+
# @param user_dirs [Array<String>] Real paths of the user tool directories
|
|
199
|
+
# @param site_dirs [Array<String>] Real paths of the site tool directories
|
|
200
|
+
#
|
|
201
|
+
def add_global_sources(groups, home_dir, user_dirs, site_dirs)
|
|
202
|
+
added_dirs = []
|
|
203
|
+
if groups.include?("home") && home_dir
|
|
204
|
+
add_search_path(home_dir)
|
|
205
|
+
home_toys_dir = real_directory(::File.join(home_dir, TOPLEVEL_TOOL_DIR_NAME))
|
|
206
|
+
added_dirs << home_toys_dir if home_toys_dir
|
|
207
|
+
end
|
|
208
|
+
tool_dirs = []
|
|
209
|
+
tool_dirs.concat(user_dirs) if groups.include?("user")
|
|
210
|
+
tool_dirs.concat(site_dirs) if groups.include?("site")
|
|
211
|
+
tool_dirs.each do |dir|
|
|
212
|
+
next if added_dirs.include?(dir) || !::File.readable?(dir)
|
|
213
|
+
added_dirs << dir
|
|
214
|
+
add_source(SourceSpec.path(dir))
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
##
|
|
219
|
+
# Returns the directories searched by the upward walk from the given
|
|
220
|
+
# directory, or none if the directory is inside a global tool directory.
|
|
221
|
+
#
|
|
222
|
+
# @param cur_dir [String] The starting directory
|
|
223
|
+
# @param home_dir [String,nil] The real path of the home directory
|
|
224
|
+
# @param global_tool_dirs [Array<String>] Real paths of the global tool
|
|
225
|
+
# directories
|
|
226
|
+
# @return [Array<String>]
|
|
227
|
+
#
|
|
228
|
+
def upward_walk_dirs(cur_dir, home_dir, global_tool_dirs)
|
|
229
|
+
cur_dir = real_directory(cur_dir) || ::File.expand_path(cur_dir)
|
|
230
|
+
cur_dir = skip_toys_dir(cur_dir, TOPLEVEL_TOOL_DIR_NAME)
|
|
231
|
+
return [] if global_tool_dirs.any? { |dir| path_within?(cur_dir, dir) }
|
|
232
|
+
walk_up(cur_dir, home_dir)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
##
|
|
236
|
+
# Returns the directories visited by the upward walk, starting at the
|
|
237
|
+
# given directory and stopping before the given terminating directory or
|
|
238
|
+
# after the root.
|
|
239
|
+
#
|
|
240
|
+
# @param start [String] The starting directory
|
|
241
|
+
# @param terminate [String,nil] The directory to stop before
|
|
242
|
+
# @return [Array<String>]
|
|
243
|
+
#
|
|
244
|
+
def walk_up(start, terminate)
|
|
245
|
+
dirs = []
|
|
246
|
+
dir = start
|
|
247
|
+
loop do
|
|
248
|
+
break if dir == terminate
|
|
249
|
+
dirs << dir
|
|
250
|
+
parent = ::File.dirname(dir)
|
|
251
|
+
break if parent == dir
|
|
252
|
+
dir = parent
|
|
253
|
+
end
|
|
254
|
+
dirs
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
##
|
|
258
|
+
# Determines whether the given path is the given directory or is inside
|
|
259
|
+
# it, comparing whole path components.
|
|
260
|
+
#
|
|
261
|
+
# @param path [String] The path to check
|
|
262
|
+
# @param dir [String] The directory
|
|
263
|
+
# @return [boolean]
|
|
264
|
+
#
|
|
265
|
+
def path_within?(path, dir)
|
|
266
|
+
loop do
|
|
267
|
+
return true if path == dir
|
|
268
|
+
parent = ::File.dirname(path)
|
|
269
|
+
return false if parent == path
|
|
270
|
+
path = parent
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
##
|
|
275
|
+
# Returns the real path of the given directory, or nil if it does not
|
|
276
|
+
# exist or is not a directory.
|
|
277
|
+
#
|
|
278
|
+
# @param path [String] The directory path
|
|
279
|
+
# @return [String,nil]
|
|
280
|
+
#
|
|
281
|
+
def real_directory(path)
|
|
282
|
+
return nil unless ::File.directory?(path)
|
|
283
|
+
::File.realpath(path)
|
|
284
|
+
rescue ::SystemCallError
|
|
285
|
+
nil
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
##
|
|
289
|
+
# Warns if the removed `TOYS_PATH` environment variable is set.
|
|
290
|
+
#
|
|
291
|
+
def warn_removed_global_paths
|
|
292
|
+
return if ::ENV["TOYS_PATH"].to_s.empty?
|
|
293
|
+
Warnings.warn(:toys_path_removed,
|
|
294
|
+
"TOYS_PATH is no longer supported and is ignored. To relocate global tool" \
|
|
295
|
+
" directories, set XDG_CONFIG_HOME or XDG_CONFIG_DIRS. To suppress them, set" \
|
|
296
|
+
" #{GLOBAL_SOURCES_ENV}. To load tools from a path once, use `toys do --path`.",
|
|
297
|
+
max_count: 1)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
##
|
|
301
|
+
# Warns if the removed `/etc` toys file or directory exists and was not
|
|
302
|
+
# loaded by the upward walk.
|
|
303
|
+
#
|
|
304
|
+
# @param walk_dirs [Array<String>] The directories visited by the walk
|
|
305
|
+
#
|
|
306
|
+
def warn_etc_toys_files(walk_dirs)
|
|
307
|
+
etc_dir = real_directory("/etc")
|
|
308
|
+
return if etc_dir.nil? || walk_dirs.include?(etc_dir)
|
|
309
|
+
file_path = ::File.join(etc_dir, TOPLEVEL_TOOL_FILE_NAME)
|
|
310
|
+
dir_path = ::File.join(etc_dir, TOPLEVEL_TOOL_DIR_NAME)
|
|
311
|
+
return unless ::File.exist?(file_path) || ::File.exist?(dir_path)
|
|
312
|
+
Warnings.warn(:etc_toys_removed,
|
|
313
|
+
"/etc/#{TOPLEVEL_TOOL_FILE_NAME} and /etc/#{TOPLEVEL_TOOL_DIR_NAME} are no longer" \
|
|
314
|
+
" loaded. Move global tools into the /etc/xdg/toys directory instead.",
|
|
315
|
+
max_count: 1)
|
|
316
|
+
end
|
|
317
|
+
|
|
148
318
|
##
|
|
149
319
|
# Step out of any toys dir.
|
|
150
320
|
#
|
|
@@ -165,21 +335,6 @@ module Toys
|
|
|
165
335
|
end
|
|
166
336
|
end
|
|
167
337
|
|
|
168
|
-
##
|
|
169
|
-
# Returns the default set of global source directories.
|
|
170
|
-
#
|
|
171
|
-
# @return [Array<String>]
|
|
172
|
-
#
|
|
173
|
-
def default_global_dirs
|
|
174
|
-
paths = ::ENV[TOYS_PATH_ENV].to_s.split(::File::PATH_SEPARATOR)
|
|
175
|
-
paths = [::Dir.home, "/etc"] if paths.empty?
|
|
176
|
-
paths
|
|
177
|
-
.compact
|
|
178
|
-
.uniq
|
|
179
|
-
.select { |path| ::File.directory?(path) && ::File.readable?(path) }
|
|
180
|
-
.map { |path| ::File.realpath(::File.expand_path(path)) }
|
|
181
|
-
end
|
|
182
|
-
|
|
183
338
|
##
|
|
184
339
|
# Returns the middleware for the standard Toys CLI.
|
|
185
340
|
#
|
data/lib/toys/version.rb
CHANGED
data/share/bash-completion.sh
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: toys
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.25.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Azuma
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.25.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.25.0
|
|
26
26
|
description: Toys is a configurable command line tool. Write commands in Ruby using
|
|
27
27
|
a simple DSL, and Toys will provide the command line executable and take care of
|
|
28
28
|
all the details such as argument parsing, online help, and error reporting. Toys
|
|
@@ -108,6 +108,7 @@ files:
|
|
|
108
108
|
- core-docs/toys/utils/standard_ui.rb
|
|
109
109
|
- core-docs/toys/utils/terminal.rb
|
|
110
110
|
- core-docs/toys/utils/xdg.rb
|
|
111
|
+
- core-docs/toys/warnings.rb
|
|
111
112
|
- core-docs/toys/wrappable_string.rb
|
|
112
113
|
- docs/guide.md
|
|
113
114
|
- lib/toys.rb
|
|
@@ -130,10 +131,10 @@ homepage: https://github.com/dazuma/toys
|
|
|
130
131
|
licenses:
|
|
131
132
|
- MIT
|
|
132
133
|
metadata:
|
|
133
|
-
changelog_uri: https://dazuma.github.io/toys/gems/toys/v0.
|
|
134
|
-
source_code_uri: https://github.com/dazuma/toys/tree/toys/v0.
|
|
134
|
+
changelog_uri: https://dazuma.github.io/toys/gems/toys/v0.25.0/file.CHANGELOG.html
|
|
135
|
+
source_code_uri: https://github.com/dazuma/toys/tree/toys/v0.25.0/toys
|
|
135
136
|
bug_tracker_uri: https://github.com/dazuma/toys/issues
|
|
136
|
-
documentation_uri: https://dazuma.github.io/toys/gems/toys/v0.
|
|
137
|
+
documentation_uri: https://dazuma.github.io/toys/gems/toys/v0.25.0
|
|
137
138
|
rdoc_options: []
|
|
138
139
|
require_paths:
|
|
139
140
|
- lib
|
|
@@ -148,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
148
149
|
- !ruby/object:Gem::Version
|
|
149
150
|
version: '0'
|
|
150
151
|
requirements: []
|
|
151
|
-
rubygems_version: 4.0.
|
|
152
|
+
rubygems_version: 4.0.20
|
|
152
153
|
specification_version: 4
|
|
153
154
|
summary: A configurable command line tool
|
|
154
155
|
test_files: []
|