toys-core 0.11.2 → 0.12.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 +46 -1
- data/README.md +1 -1
- data/lib/toys-core.rb +4 -1
- data/lib/toys/acceptor.rb +3 -3
- data/lib/toys/arg_parser.rb +6 -7
- data/lib/toys/cli.rb +44 -14
- data/lib/toys/compat.rb +19 -22
- data/lib/toys/completion.rb +3 -1
- data/lib/toys/context.rb +2 -2
- data/lib/toys/core.rb +1 -1
- data/lib/toys/dsl/base.rb +85 -0
- data/lib/toys/dsl/flag.rb +3 -3
- data/lib/toys/dsl/flag_group.rb +7 -7
- data/lib/toys/dsl/internal.rb +206 -0
- data/lib/toys/dsl/positional_arg.rb +3 -3
- data/lib/toys/dsl/tool.rb +174 -216
- data/lib/toys/errors.rb +1 -0
- data/lib/toys/flag.rb +15 -18
- data/lib/toys/flag_group.rb +5 -4
- data/lib/toys/input_file.rb +4 -4
- data/lib/toys/loader.rb +189 -50
- data/lib/toys/middleware.rb +1 -1
- data/lib/toys/mixin.rb +2 -2
- data/lib/toys/positional_arg.rb +3 -3
- data/lib/toys/settings.rb +900 -0
- data/lib/toys/source_info.rb +121 -18
- data/lib/toys/standard_middleware/apply_config.rb +5 -4
- data/lib/toys/standard_middleware/set_default_descriptions.rb +18 -18
- data/lib/toys/standard_middleware/show_help.rb +17 -5
- data/lib/toys/standard_mixins/bundler.rb +5 -1
- data/lib/toys/standard_mixins/exec.rb +22 -15
- data/lib/toys/standard_mixins/git_cache.rb +48 -0
- data/lib/toys/standard_mixins/xdg.rb +56 -0
- data/lib/toys/template.rb +2 -2
- data/lib/toys/{tool.rb → tool_definition.rb} +100 -41
- data/lib/toys/utils/exec.rb +37 -16
- data/lib/toys/utils/gems.rb +48 -14
- data/lib/toys/utils/git_cache.rb +184 -0
- data/lib/toys/utils/help_text.rb +90 -34
- data/lib/toys/utils/terminal.rb +1 -1
- data/lib/toys/utils/xdg.rb +293 -0
- metadata +15 -8
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module Toys
|
6
|
+
module StandardMixins
|
7
|
+
##
|
8
|
+
# A mixin that provides a git cache.
|
9
|
+
#
|
10
|
+
# This mixin provides an instance of {Toys::Utils::GitCache}, providing
|
11
|
+
# cached access to files from a remote git repo.
|
12
|
+
#
|
13
|
+
# Example usage:
|
14
|
+
#
|
15
|
+
# include :git_cache
|
16
|
+
#
|
17
|
+
# def run
|
18
|
+
# # Pull and cache the HEAD commit from the Toys repo.
|
19
|
+
# dir = git_cache.find("https://github.com/dazuma/toys.git")
|
20
|
+
# # Display the contents of the readme file.
|
21
|
+
# puts File.read(File.join(dir, "README.md"))
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
module GitCache
|
25
|
+
include Mixin
|
26
|
+
|
27
|
+
##
|
28
|
+
# Context key for the GitCache object.
|
29
|
+
# @return [Object]
|
30
|
+
#
|
31
|
+
KEY = ::Object.new.freeze
|
32
|
+
|
33
|
+
on_initialize do
|
34
|
+
require "toys/utils/git_cache"
|
35
|
+
self[KEY] = Utils::GitCache.new
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Access the builtin GitCache.
|
40
|
+
#
|
41
|
+
# @return [Toys::Utils::GitCache]
|
42
|
+
#
|
43
|
+
def git_cache
|
44
|
+
self[KEY]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module Toys
|
6
|
+
module StandardMixins
|
7
|
+
##
|
8
|
+
# A mixin that provides tools for working with the XDG Base Directory
|
9
|
+
# Specification.
|
10
|
+
#
|
11
|
+
# This mixin provides an instance of {Toys::Utils::XDG}, which includes
|
12
|
+
# utility methods that locate base directories and search paths for
|
13
|
+
# application state, configuration, caches, and other data, according to
|
14
|
+
# the [XDG Base Directory Spec version
|
15
|
+
# 0.8](https://specifications.freedesktop.org/basedir-spec/0.8/).
|
16
|
+
#
|
17
|
+
# Example usage:
|
18
|
+
#
|
19
|
+
# include :xdg
|
20
|
+
#
|
21
|
+
# def run
|
22
|
+
# # Get config file paths, in order from most to least inportant
|
23
|
+
# config_files = xdg.lookup_config("my-config.toml")
|
24
|
+
# config_files.each { |path| read_my_config(path) }
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
module XDG
|
28
|
+
include Mixin
|
29
|
+
|
30
|
+
##
|
31
|
+
# Context key for the XDG object.
|
32
|
+
# @return [Object]
|
33
|
+
#
|
34
|
+
KEY = ::Object.new.freeze
|
35
|
+
|
36
|
+
on_initialize do
|
37
|
+
require "toys/utils/xdg"
|
38
|
+
self[KEY] = Utils::XDG.new
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Access XDG utility methods.
|
43
|
+
#
|
44
|
+
# @return [Toys::Utils::XDG]
|
45
|
+
#
|
46
|
+
def xdg
|
47
|
+
self[KEY]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# An alternate name for the {XDG} module
|
53
|
+
#
|
54
|
+
Xdg = XDG
|
55
|
+
end
|
56
|
+
end
|
data/lib/toys/template.rb
CHANGED
@@ -10,7 +10,7 @@ module Toys
|
|
10
10
|
# Templates will often support configuration; for example the minitest
|
11
11
|
# template lets you configure the paths to the test files.
|
12
12
|
#
|
13
|
-
#
|
13
|
+
# ### Usage
|
14
14
|
#
|
15
15
|
# To create a template, define a class and include this module.
|
16
16
|
# The class defines the "configuration" of the template. If your template
|
@@ -25,7 +25,7 @@ module Toys
|
|
25
25
|
# this block are "inserted" into the user's configuration. The template
|
26
26
|
# object is passed to the block so you have access to the template options.
|
27
27
|
#
|
28
|
-
#
|
28
|
+
# ### Example
|
29
29
|
#
|
30
30
|
# This is a simple template that generates a "hello" tool. The tool simply
|
31
31
|
# prints a `"Hello, #{name}!"` greeting. The name is set as a template
|
@@ -4,22 +4,25 @@ require "set"
|
|
4
4
|
|
5
5
|
module Toys
|
6
6
|
##
|
7
|
-
# A
|
7
|
+
# A ToolDefinition describes a single command that can be invoked using Toys.
|
8
8
|
# It has a name, a series of one or more words that you use to identify
|
9
9
|
# the tool on the command line. It also has a set of formal flags and
|
10
10
|
# command line arguments supported, and a block that gets run when the
|
11
11
|
# tool is executed.
|
12
12
|
#
|
13
|
-
class
|
13
|
+
class ToolDefinition
|
14
14
|
##
|
15
15
|
# Create a new tool.
|
16
16
|
# Should be created only from the DSL via the Loader.
|
17
17
|
# @private
|
18
18
|
#
|
19
|
-
def initialize(
|
19
|
+
def initialize(parent, full_name, priority, source_root, middleware_stack, middleware_lookup,
|
20
|
+
tool_class = nil)
|
20
21
|
@parent = parent
|
22
|
+
@settings = Settings.new(parent: parent&.settings)
|
21
23
|
@full_name = full_name.dup.freeze
|
22
24
|
@priority = priority
|
25
|
+
@source_root = source_root
|
23
26
|
@built_middleware = middleware_stack.build(middleware_lookup)
|
24
27
|
@subtool_middleware_stack = middleware_stack.dup
|
25
28
|
|
@@ -28,7 +31,9 @@ module Toys
|
|
28
31
|
@templates = {}
|
29
32
|
@completions = {}
|
30
33
|
|
31
|
-
|
34
|
+
@precreated_class = tool_class
|
35
|
+
|
36
|
+
reset_definition
|
32
37
|
end
|
33
38
|
|
34
39
|
##
|
@@ -37,8 +42,8 @@ module Toys
|
|
37
42
|
# Should be called only from the DSL.
|
38
43
|
# @private
|
39
44
|
#
|
40
|
-
def reset_definition
|
41
|
-
@tool_class =
|
45
|
+
def reset_definition
|
46
|
+
@tool_class = @precreated_class || create_class
|
42
47
|
|
43
48
|
@source_info = nil
|
44
49
|
@definition_finished = false
|
@@ -72,6 +77,13 @@ module Toys
|
|
72
77
|
@completion = DefaultCompletion.new
|
73
78
|
end
|
74
79
|
|
80
|
+
##
|
81
|
+
# Settings for this tool
|
82
|
+
#
|
83
|
+
# @return [Toys::Tool::Settings]
|
84
|
+
#
|
85
|
+
attr_reader :settings
|
86
|
+
|
75
87
|
##
|
76
88
|
# The name of the tool as an array of strings.
|
77
89
|
# This array may not be modified.
|
@@ -87,6 +99,13 @@ module Toys
|
|
87
99
|
#
|
88
100
|
attr_reader :priority
|
89
101
|
|
102
|
+
##
|
103
|
+
# The root source info defining this tool, or nil if there is no source.
|
104
|
+
#
|
105
|
+
# @return [Toys::SourceInfo,nil]
|
106
|
+
#
|
107
|
+
attr_reader :source_root
|
108
|
+
|
90
109
|
##
|
91
110
|
# The tool class.
|
92
111
|
#
|
@@ -217,14 +236,14 @@ module Toys
|
|
217
236
|
#
|
218
237
|
# When reading, this may return an instance of one of the subclasses of
|
219
238
|
# {Toys::Completion::Base}, or a Proc that duck-types it. Generally, this
|
220
|
-
# defaults to a {Toys::
|
221
|
-
# algorithm that finds appropriate completions from flags,
|
222
|
-
# arguments, and subtools.
|
239
|
+
# defaults to a {Toys::ToolDefinition::DefaultCompletion}, providing a
|
240
|
+
# standard algorithm that finds appropriate completions from flags,
|
241
|
+
# positional arguments, and subtools.
|
223
242
|
#
|
224
243
|
# When setting, you may pass any of the following:
|
225
244
|
# * `nil` or `:default` which sets the value to a default instance.
|
226
|
-
# * A Hash of options to pass to the
|
227
|
-
# constructor.
|
245
|
+
# * A Hash of options to pass to the
|
246
|
+
# {Toys::ToolDefinition::DefaultCompletion} constructor.
|
228
247
|
# * Any other form recognized by {Toys::Completion.create}.
|
229
248
|
#
|
230
249
|
# @return [Toys::Completion::Base,Proc]
|
@@ -408,7 +427,7 @@ module Toys
|
|
408
427
|
# Get the named acceptor from this tool or its ancestors.
|
409
428
|
#
|
410
429
|
# @param name [String] The acceptor name.
|
411
|
-
# @return [
|
430
|
+
# @return [Toys::Acceptor::Base] The acceptor.
|
412
431
|
# @return [nil] if no acceptor of the given name is found.
|
413
432
|
#
|
414
433
|
def lookup_acceptor(name)
|
@@ -441,7 +460,7 @@ module Toys
|
|
441
460
|
# Get the named completion from this tool or its ancestors.
|
442
461
|
#
|
443
462
|
# @param name [String] The completion name
|
444
|
-
# @return [
|
463
|
+
# @return [Toys::Completion::Base,Proc] The completion proc.
|
445
464
|
# @return [nil] if no completion of the given name is found.
|
446
465
|
#
|
447
466
|
def lookup_completion(name)
|
@@ -451,11 +470,31 @@ module Toys
|
|
451
470
|
##
|
452
471
|
# Include the given mixin in the tool class.
|
453
472
|
#
|
454
|
-
#
|
473
|
+
# The mixin must be given as a module. You can use {#lookup_mixin} or
|
474
|
+
# {Loader#resolve_standard_mixin} to resolve named mixins.
|
475
|
+
#
|
476
|
+
# @param mod [Module] The mixin module
|
455
477
|
# @return [self]
|
456
478
|
#
|
457
|
-
def include_mixin(
|
458
|
-
|
479
|
+
def include_mixin(mod, *args, **kwargs)
|
480
|
+
check_definition_state
|
481
|
+
if tool_class.included_modules.include?(mod)
|
482
|
+
raise ToolDefinitionError, "Mixin already included: #{mod.name}"
|
483
|
+
end
|
484
|
+
@includes_modules = true
|
485
|
+
if tool_class.respond_to?(:super_include)
|
486
|
+
tool_class.super_include(mod)
|
487
|
+
else
|
488
|
+
tool_class.include(mod)
|
489
|
+
end
|
490
|
+
if mod.respond_to?(:initializer)
|
491
|
+
callback = mod.initializer
|
492
|
+
add_initializer(callback, *args, **kwargs) if callback
|
493
|
+
end
|
494
|
+
if mod.respond_to?(:inclusion)
|
495
|
+
callback = mod.inclusion
|
496
|
+
tool_class.class_exec(*args, **kwargs, &callback) if callback
|
497
|
+
end
|
459
498
|
self
|
460
499
|
end
|
461
500
|
|
@@ -565,7 +604,7 @@ module Toys
|
|
565
604
|
# completion.
|
566
605
|
#
|
567
606
|
# @param name [String] The name of the completion.
|
568
|
-
# @param completion [Proc,
|
607
|
+
# @param completion [Proc,Toys::Completion::Base,Object] The completion to
|
569
608
|
# add. You can provide either a completion object, or a spec understood
|
570
609
|
# by {Toys::Completion.create}.
|
571
610
|
# @param options [Hash] Additional options to pass to the completion.
|
@@ -669,11 +708,12 @@ module Toys
|
|
669
708
|
#
|
670
709
|
# @param type [Symbol] The type of group. Default is `:optional`.
|
671
710
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
672
|
-
# description for the group. See {Toys::
|
673
|
-
# of allowed formats. Defaults to `"Flags"`.
|
711
|
+
# description for the group. See {Toys::ToolDefinition#desc} for a
|
712
|
+
# description of allowed formats. Defaults to `"Flags"`.
|
674
713
|
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
675
|
-
# Long description for the flag group. See
|
676
|
-
# a description of allowed
|
714
|
+
# Long description for the flag group. See
|
715
|
+
# {Toys::ToolDefinition#long_desc} for a description of allowed
|
716
|
+
# formats. Defaults to the empty array.
|
677
717
|
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
678
718
|
# name.
|
679
719
|
# @param report_collisions [Boolean] If `true`, raise an exception if a
|
@@ -741,11 +781,11 @@ module Toys
|
|
741
781
|
# this flag. You may provide a group name, a FlagGroup object, or
|
742
782
|
# `nil` which denotes the default group.
|
743
783
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
744
|
-
# description for the flag. See {Toys::
|
745
|
-
# allowed formats. Defaults to the empty string.
|
784
|
+
# description for the flag. See {Toys::ToolDefinition#desc} for a
|
785
|
+
# description of allowed formats. Defaults to the empty string.
|
746
786
|
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
747
|
-
# Long description for the flag. See {Toys::
|
748
|
-
# description of allowed formats. Defaults to the empty array.
|
787
|
+
# Long description for the flag. See {Toys::ToolDefinition#long_desc}
|
788
|
+
# for a description of allowed formats. Defaults to the empty array.
|
749
789
|
# @param display_name [String] A display name for this flag, used in help
|
750
790
|
# text and error messages.
|
751
791
|
# @return [self]
|
@@ -808,11 +848,11 @@ module Toys
|
|
808
848
|
# @param display_name [String] A name to use for display (in help text and
|
809
849
|
# error reports). Defaults to the key in upper case.
|
810
850
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
811
|
-
# description for the arg. See {Toys::
|
812
|
-
# allowed formats. Defaults to the empty string.
|
851
|
+
# description for the arg. See {Toys::ToolDefinition#desc} for a
|
852
|
+
# description of allowed formats. Defaults to the empty string.
|
813
853
|
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
814
|
-
# Long description for the arg. See {Toys::
|
815
|
-
# description of allowed formats. Defaults to the empty array.
|
854
|
+
# Long description for the arg. See {Toys::ToolDefinition#long_desc}
|
855
|
+
# for a description of allowed formats. Defaults to the empty array.
|
816
856
|
# @return [self]
|
817
857
|
#
|
818
858
|
def add_required_arg(key, accept: nil, complete: nil, display_name: nil,
|
@@ -846,11 +886,11 @@ module Toys
|
|
846
886
|
# @param display_name [String] A name to use for display (in help text and
|
847
887
|
# error reports). Defaults to the key in upper case.
|
848
888
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
849
|
-
# description for the arg. See {Toys::
|
850
|
-
# allowed formats. Defaults to the empty string.
|
889
|
+
# description for the arg. See {Toys::ToolDefinition#desc} for a
|
890
|
+
# description of allowed formats. Defaults to the empty string.
|
851
891
|
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
852
|
-
# Long description for the arg. See {Toys::
|
853
|
-
# description of allowed formats. Defaults to the empty array.
|
892
|
+
# Long description for the arg. See {Toys::ToolDefinition#long_desc}
|
893
|
+
# for a description of allowed formats. Defaults to the empty array.
|
854
894
|
# @return [self]
|
855
895
|
#
|
856
896
|
def add_optional_arg(key, default: nil, accept: nil, complete: nil,
|
@@ -884,11 +924,11 @@ module Toys
|
|
884
924
|
# @param display_name [String] A name to use for display (in help text and
|
885
925
|
# error reports). Defaults to the key in upper case.
|
886
926
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
887
|
-
# description for the arg. See {Toys::
|
888
|
-
# allowed formats. Defaults to the empty string.
|
927
|
+
# description for the arg. See {Toys::ToolDefinition#desc} for a
|
928
|
+
# description of allowed formats. Defaults to the empty string.
|
889
929
|
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
890
|
-
# Long description for the arg. See {Toys::
|
891
|
-
# description of allowed formats. Defaults to the empty array.
|
930
|
+
# Long description for the arg. See {Toys::ToolDefinition#long_desc}
|
931
|
+
# for a description of allowed formats. Defaults to the empty array.
|
892
932
|
# @return [self]
|
893
933
|
#
|
894
934
|
def set_remaining_args(key, default: [], accept: nil, complete: nil,
|
@@ -910,7 +950,9 @@ module Toys
|
|
910
950
|
#
|
911
951
|
def run_handler=(proc)
|
912
952
|
check_definition_state(is_method: true)
|
913
|
-
|
953
|
+
tool_class.class_eval do
|
954
|
+
define_method(:run, &proc)
|
955
|
+
end
|
914
956
|
end
|
915
957
|
|
916
958
|
##
|
@@ -966,7 +1008,7 @@ module Toys
|
|
966
1008
|
end
|
967
1009
|
|
968
1010
|
##
|
969
|
-
# Set the completion strategy for this
|
1011
|
+
# Set the completion strategy for this ToolDefinition.
|
970
1012
|
#
|
971
1013
|
# See {#completion} for details.
|
972
1014
|
#
|
@@ -1056,7 +1098,7 @@ module Toys
|
|
1056
1098
|
def finish_definition(loader)
|
1057
1099
|
unless @definition_finished
|
1058
1100
|
ContextualError.capture("Error installing tool middleware!", tool_name: full_name) do
|
1059
|
-
config_proc = proc {}
|
1101
|
+
config_proc = proc { nil }
|
1060
1102
|
@built_middleware.reverse_each do |middleware|
|
1061
1103
|
config_proc = make_config_proc(middleware, loader, config_proc)
|
1062
1104
|
end
|
@@ -1120,6 +1162,7 @@ module Toys
|
|
1120
1162
|
def initialize(complete_subtools: true, include_hidden_subtools: false,
|
1121
1163
|
complete_args: true, complete_flags: true, complete_flag_values: true,
|
1122
1164
|
delegation_target: nil)
|
1165
|
+
super()
|
1123
1166
|
@complete_subtools = complete_subtools
|
1124
1167
|
@include_hidden_subtools = include_hidden_subtools
|
1125
1168
|
@complete_flags = complete_flags
|
@@ -1206,7 +1249,7 @@ module Toys
|
|
1206
1249
|
return unless arg_parser.flags_allowed?
|
1207
1250
|
active_flag_def = arg_parser.active_flag_def
|
1208
1251
|
return if active_flag_def && active_flag_def.value_type == :required
|
1209
|
-
match = /\A(--\w[
|
1252
|
+
match = /\A(--\w[?\w-]*)=(.*)\z/.match(context.fragment_prefix)
|
1210
1253
|
return unless match
|
1211
1254
|
flag_value_context = context.with(fragment_prefix: match[2])
|
1212
1255
|
flag_def = flag_value_context.tool.resolve_flag(match[1]).unique_flag
|
@@ -1287,8 +1330,24 @@ module Toys
|
|
1287
1330
|
end
|
1288
1331
|
end
|
1289
1332
|
|
1333
|
+
##
|
1334
|
+
# Tool-based settings class.
|
1335
|
+
#
|
1336
|
+
# The following settings are supported:
|
1337
|
+
#
|
1338
|
+
# * `propagate_helper_methods` (_Boolean_) - Whether subtools should
|
1339
|
+
# inherit methods defined by parent tools. Defaults to `false`.
|
1340
|
+
#
|
1341
|
+
class Settings < ::Toys::Settings
|
1342
|
+
settings_attr :propagate_helper_methods, default: false
|
1343
|
+
end
|
1344
|
+
|
1290
1345
|
private
|
1291
1346
|
|
1347
|
+
def create_class
|
1348
|
+
::Class.new(@parent&.settings&.propagate_helper_methods ? @parent.tool_class : ::Toys::Context)
|
1349
|
+
end
|
1350
|
+
|
1292
1351
|
def make_config_proc(middleware, loader, next_config)
|
1293
1352
|
if middleware.respond_to?(:config)
|
1294
1353
|
proc { middleware.config(self, loader, &next_config) }
|
data/lib/toys/utils/exec.rb
CHANGED
@@ -16,8 +16,6 @@ module Toys
|
|
16
16
|
# This class is not loaded by default. Before using it directly, you should
|
17
17
|
# `require "toys/utils/exec"`
|
18
18
|
#
|
19
|
-
# ## Features
|
20
|
-
#
|
21
19
|
# ### Controlling processes
|
22
20
|
#
|
23
21
|
# A process can be started in the *foreground* or the *background*. If you
|
@@ -138,7 +136,7 @@ module Toys
|
|
138
136
|
# end
|
139
137
|
# exec_service.exec(["git", "init"], result_callback: my_callback)
|
140
138
|
#
|
141
|
-
#
|
139
|
+
# ### Configuration options
|
142
140
|
#
|
143
141
|
# A variety of options can be used to control subprocesses. These can be
|
144
142
|
# provided to any method that starts a subprocess. Youc an also set
|
@@ -250,13 +248,14 @@ module Toys
|
|
250
248
|
exec_opts = Opts.new(@default_opts).add(opts)
|
251
249
|
spawn_cmd =
|
252
250
|
if cmd.is_a?(::Array)
|
253
|
-
if cmd.size
|
254
|
-
|
251
|
+
if cmd.size > 1
|
252
|
+
binary = canonical_binary_spec(cmd.first, exec_opts)
|
253
|
+
[binary] + cmd[1..-1].map(&:to_s)
|
255
254
|
else
|
256
|
-
cmd
|
255
|
+
[canonical_binary_spec(Array(cmd.first), exec_opts)]
|
257
256
|
end
|
258
257
|
else
|
259
|
-
[cmd]
|
258
|
+
[cmd.to_s]
|
260
259
|
end
|
261
260
|
executor = Executor.new(exec_opts, spawn_cmd, block)
|
262
261
|
executor.execute
|
@@ -796,7 +795,7 @@ module Toys
|
|
796
795
|
# {Result#success?} or {Result#error?} will return true, and
|
797
796
|
# {Result.exit_code} will return the numeric exit code.
|
798
797
|
# * The process executed but was terminated by an uncaught signal.
|
799
|
-
# {Result#signaled?} will return true, and {Result#
|
798
|
+
# {Result#signaled?} will return true, and {Result#signal_code} will
|
800
799
|
# return the numeric signal code.
|
801
800
|
#
|
802
801
|
class Result
|
@@ -848,6 +847,8 @@ module Toys
|
|
848
847
|
# The exception raised if a process couldn't be started.
|
849
848
|
#
|
850
849
|
# Exactly one of {#exception} and {#status} will be non-nil.
|
850
|
+
# Exactly one of {#exception}, {#exit_code}, or {#signal_code} will be
|
851
|
+
# non-nil.
|
851
852
|
#
|
852
853
|
# @return [Exception] The exception raised from process start.
|
853
854
|
# @return [nil] if the process started successfully.
|
@@ -857,7 +858,7 @@ module Toys
|
|
857
858
|
##
|
858
859
|
# The numeric status code for a process that exited normally,
|
859
860
|
#
|
860
|
-
# Exactly one of {#exception}, {#exit_code},
|
861
|
+
# Exactly one of {#exception}, {#exit_code}, or {#signal_code} will be
|
861
862
|
# non-nil.
|
862
863
|
#
|
863
864
|
# @return [Integer] the numeric status code, if the process started
|
@@ -872,16 +873,17 @@ module Toys
|
|
872
873
|
##
|
873
874
|
# The numeric signal code that caused process termination.
|
874
875
|
#
|
875
|
-
# Exactly one of {#exception}, {#exit_code},
|
876
|
+
# Exactly one of {#exception}, {#exit_code}, or {#signal_code} will be
|
876
877
|
# non-nil.
|
877
878
|
#
|
878
879
|
# @return [Integer] The signal that caused the process to terminate.
|
879
880
|
# @return [nil] if the process did not start successfully, or executed
|
880
881
|
# and exited with a normal exit code.
|
881
882
|
#
|
882
|
-
def
|
883
|
+
def signal_code
|
883
884
|
status&.termsig
|
884
885
|
end
|
886
|
+
alias term_signal signal_code
|
885
887
|
|
886
888
|
##
|
887
889
|
# Returns true if the subprocess failed to start, or false if the
|
@@ -900,7 +902,7 @@ module Toys
|
|
900
902
|
# @return [Boolean]
|
901
903
|
#
|
902
904
|
def signaled?
|
903
|
-
!
|
905
|
+
!signal_code.nil?
|
904
906
|
end
|
905
907
|
|
906
908
|
##
|
@@ -968,12 +970,19 @@ module Toys
|
|
968
970
|
def log_command
|
969
971
|
logger = @config_opts[:logger]
|
970
972
|
if logger && @config_opts[:log_level] != false
|
971
|
-
cmd_str = @config_opts[:log_cmd]
|
972
|
-
cmd_str ||= @spawn_cmd.size == 1 ? @spawn_cmd.first : @spawn_cmd.inspect if @spawn_cmd
|
973
|
+
cmd_str = @config_opts[:log_cmd] || default_log_str(@spawn_cmd)
|
973
974
|
logger.add(@config_opts[:log_level] || ::Logger::INFO, cmd_str) if cmd_str
|
974
975
|
end
|
975
976
|
end
|
976
977
|
|
978
|
+
def default_log_str(spawn_cmd)
|
979
|
+
return nil unless spawn_cmd
|
980
|
+
return spawn_cmd.first if spawn_cmd.size == 1 && spawn_cmd.first.is_a?(::String)
|
981
|
+
cmd_binary = spawn_cmd.first
|
982
|
+
cmd_binary = cmd_binary.first if cmd_binary.is_a?(::Array)
|
983
|
+
([cmd_binary] + spawn_cmd[1..-1]).inspect
|
984
|
+
end
|
985
|
+
|
977
986
|
def start_with_controller
|
978
987
|
pid =
|
979
988
|
begin
|
@@ -1082,9 +1091,10 @@ module Toys
|
|
1082
1091
|
|
1083
1092
|
def interpret_out_array_within_fork(stream)
|
1084
1093
|
if stream.first == :child
|
1085
|
-
|
1094
|
+
case stream[1]
|
1095
|
+
when :err
|
1086
1096
|
$stderr
|
1087
|
-
|
1097
|
+
when :out
|
1088
1098
|
$stdout
|
1089
1099
|
end
|
1090
1100
|
else
|
@@ -1300,6 +1310,17 @@ module Toys
|
|
1300
1310
|
end
|
1301
1311
|
end
|
1302
1312
|
end
|
1313
|
+
|
1314
|
+
private
|
1315
|
+
|
1316
|
+
def canonical_binary_spec(cmd, exec_opts)
|
1317
|
+
config_argv0 = exec_opts.config_opts[:argv0]
|
1318
|
+
return cmd.to_s if !config_argv0 && !cmd.is_a?(::Array)
|
1319
|
+
cmd = Array(cmd)
|
1320
|
+
actual_cmd = cmd.first
|
1321
|
+
argv0 = cmd[1] || config_argv0 || actual_cmd
|
1322
|
+
[actual_cmd.to_s, argv0.to_s]
|
1323
|
+
end
|
1303
1324
|
end
|
1304
1325
|
end
|
1305
1326
|
end
|