toys-core 0.9.4 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +2 -1
- data/CHANGELOG.md +30 -0
- data/LICENSE.md +1 -1
- data/README.md +3 -3
- data/lib/toys-core.rb +11 -21
- data/lib/toys/acceptor.rb +0 -21
- data/lib/toys/arg_parser.rb +1 -22
- data/lib/toys/cli.rb +102 -70
- data/lib/toys/compat.rb +49 -41
- data/lib/toys/completion.rb +0 -21
- data/lib/toys/context.rb +0 -23
- data/lib/toys/core.rb +1 -22
- data/lib/toys/dsl/flag.rb +0 -21
- data/lib/toys/dsl/flag_group.rb +0 -21
- data/lib/toys/dsl/positional_arg.rb +0 -21
- data/lib/toys/dsl/tool.rb +135 -51
- data/lib/toys/errors.rb +0 -21
- data/lib/toys/flag.rb +0 -21
- data/lib/toys/flag_group.rb +0 -21
- data/lib/toys/input_file.rb +0 -21
- data/lib/toys/loader.rb +41 -78
- data/lib/toys/middleware.rb +146 -77
- data/lib/toys/mixin.rb +0 -21
- data/lib/toys/module_lookup.rb +3 -26
- data/lib/toys/positional_arg.rb +0 -21
- data/lib/toys/source_info.rb +49 -38
- data/lib/toys/standard_middleware/add_verbosity_flags.rb +0 -23
- data/lib/toys/standard_middleware/apply_config.rb +42 -0
- data/lib/toys/standard_middleware/handle_usage_errors.rb +7 -28
- data/lib/toys/standard_middleware/set_default_descriptions.rb +0 -23
- data/lib/toys/standard_middleware/show_help.rb +0 -23
- data/lib/toys/standard_middleware/show_root_version.rb +0 -23
- data/lib/toys/standard_mixins/bundler.rb +89 -0
- data/lib/toys/standard_mixins/exec.rb +124 -35
- data/lib/toys/standard_mixins/fileutils.rb +0 -21
- data/lib/toys/standard_mixins/gems.rb +2 -24
- data/lib/toys/standard_mixins/highline.rb +0 -21
- data/lib/toys/standard_mixins/terminal.rb +0 -21
- data/lib/toys/template.rb +0 -21
- data/lib/toys/tool.rb +22 -34
- data/lib/toys/utils/completion_engine.rb +0 -21
- data/lib/toys/utils/exec.rb +1 -21
- data/lib/toys/utils/gems.rb +174 -63
- data/lib/toys/utils/help_text.rb +0 -21
- data/lib/toys/utils/terminal.rb +46 -37
- data/lib/toys/wrappable_string.rb +0 -21
- metadata +25 -9
@@ -1,26 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
21
|
-
# IN THE SOFTWARE.
|
22
|
-
;
|
23
|
-
|
24
3
|
module Toys
|
25
4
|
module StandardMixins
|
26
5
|
##
|
data/lib/toys/template.rb
CHANGED
@@ -1,26 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
21
|
-
# IN THE SOFTWARE.
|
22
|
-
;
|
23
|
-
|
24
3
|
module Toys
|
25
4
|
##
|
26
5
|
# A template definition. Template classes should include this module.
|
data/lib/toys/tool.rb
CHANGED
@@ -1,26 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
21
|
-
# IN THE SOFTWARE.
|
22
|
-
;
|
23
|
-
|
24
3
|
require "set"
|
25
4
|
|
26
5
|
module Toys
|
@@ -37,11 +16,12 @@ module Toys
|
|
37
16
|
# Should be created only from the DSL via the Loader.
|
38
17
|
# @private
|
39
18
|
#
|
40
|
-
def initialize(loader, parent, full_name, priority, middleware_stack)
|
19
|
+
def initialize(loader, parent, full_name, priority, middleware_stack, middleware_lookup)
|
41
20
|
@parent = parent
|
42
21
|
@full_name = full_name.dup.freeze
|
43
22
|
@priority = priority
|
44
|
-
@
|
23
|
+
@built_middleware = middleware_stack.build(middleware_lookup)
|
24
|
+
@subtool_middleware_stack = middleware_stack.dup
|
45
25
|
|
46
26
|
@acceptors = {}
|
47
27
|
@mixins = {}
|
@@ -201,11 +181,20 @@ module Toys
|
|
201
181
|
attr_reader :default_data
|
202
182
|
|
203
183
|
##
|
204
|
-
# The middleware
|
184
|
+
# The stack of middleware specs used for subtools.
|
185
|
+
#
|
186
|
+
# This array may be modified in place.
|
187
|
+
#
|
188
|
+
# @return [Array<Toys::Middleware::Spec>]
|
189
|
+
#
|
190
|
+
attr_reader :subtool_middleware_stack
|
191
|
+
|
192
|
+
##
|
193
|
+
# The stack of built middleware specs for this tool.
|
205
194
|
#
|
206
195
|
# @return [Array<Toys::Middleware>]
|
207
196
|
#
|
208
|
-
attr_reader :
|
197
|
+
attr_reader :built_middleware
|
209
198
|
|
210
199
|
##
|
211
200
|
# Info on the source of this tool.
|
@@ -473,18 +462,13 @@ module Toys
|
|
473
462
|
##
|
474
463
|
# Sets the path to the file that defines this tool.
|
475
464
|
# A tool may be defined from at most one path. If a different path is
|
476
|
-
# already set,
|
465
|
+
# already set, it is left unchanged.
|
477
466
|
#
|
478
467
|
# @param source [Toys::SourceInfo] Source info
|
479
468
|
# @return [self]
|
480
469
|
#
|
481
470
|
def lock_source(source)
|
482
|
-
|
483
|
-
raise ToolDefinitionError,
|
484
|
-
"Cannot redefine tool #{display_name.inspect} in #{source.source_name}" \
|
485
|
-
" (already defined in #{source_info.source_name})"
|
486
|
-
end
|
487
|
-
@source_info = source
|
471
|
+
@source_info ||= source
|
488
472
|
self
|
489
473
|
end
|
490
474
|
|
@@ -1073,7 +1057,7 @@ module Toys
|
|
1073
1057
|
unless @definition_finished
|
1074
1058
|
ContextualError.capture("Error installing tool middleware!", tool_name: full_name) do
|
1075
1059
|
config_proc = proc {}
|
1076
|
-
|
1060
|
+
@built_middleware.reverse_each do |middleware|
|
1077
1061
|
config_proc = make_config_proc(middleware, loader, config_proc)
|
1078
1062
|
end
|
1079
1063
|
config_proc.call
|
@@ -1306,7 +1290,11 @@ module Toys
|
|
1306
1290
|
private
|
1307
1291
|
|
1308
1292
|
def make_config_proc(middleware, loader, next_config)
|
1309
|
-
|
1293
|
+
if middleware.respond_to?(:config)
|
1294
|
+
proc { middleware.config(self, loader, &next_config) }
|
1295
|
+
else
|
1296
|
+
next_config
|
1297
|
+
end
|
1310
1298
|
end
|
1311
1299
|
|
1312
1300
|
def make_delegation_run_handler(target)
|
@@ -1,26 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
21
|
-
# IN THE SOFTWARE.
|
22
|
-
;
|
23
|
-
|
24
3
|
require "shellwords"
|
25
4
|
|
26
5
|
module Toys
|
data/lib/toys/utils/exec.rb
CHANGED
@@ -1,26 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
21
|
-
# IN THE SOFTWARE.
|
22
|
-
;
|
23
|
-
|
3
|
+
require "rbconfig"
|
24
4
|
require "logger"
|
25
5
|
require "shellwords"
|
26
6
|
|
data/lib/toys/utils/gems.rb
CHANGED
@@ -1,30 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
-
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
21
|
-
# IN THE SOFTWARE.
|
22
|
-
;
|
3
|
+
require "monitor"
|
4
|
+
require "rubygems"
|
23
5
|
|
24
6
|
module Toys
|
25
7
|
module Utils
|
26
8
|
##
|
27
|
-
# A helper
|
9
|
+
# A helper class that activates and installs gems and sets up bundler.
|
28
10
|
#
|
29
11
|
# This class is not loaded by default. Before using it directly, you should
|
30
12
|
# `require "toys/utils/gems"`
|
@@ -58,6 +40,30 @@ module Toys
|
|
58
40
|
end
|
59
41
|
end
|
60
42
|
|
43
|
+
##
|
44
|
+
# Failed to run Bundler
|
45
|
+
#
|
46
|
+
class BundlerFailedError < ::StandardError
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Could not find a Gemfile
|
51
|
+
#
|
52
|
+
class GemfileNotFoundError < BundlerFailedError
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# The bundle is not and could not be installed
|
57
|
+
#
|
58
|
+
class BundleNotInstalledError < BundlerFailedError
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Bundler has already been run; cannot do so again
|
63
|
+
#
|
64
|
+
class AlreadyBundledError < BundlerFailedError
|
65
|
+
end
|
66
|
+
|
61
67
|
##
|
62
68
|
# Activate the given gem. If it is not present, attempt to install it (or
|
63
69
|
# inform the user to update the bundle).
|
@@ -73,24 +79,42 @@ module Toys
|
|
73
79
|
##
|
74
80
|
# Create a new gem activator.
|
75
81
|
#
|
76
|
-
# @param
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
82
|
+
# @param on_missing [:confirm,:error,:install] What to do if a needed gem
|
83
|
+
# is not installed. Possible values:
|
84
|
+
# * `:confirm` - prompt the user on whether to install
|
85
|
+
# * `:error` - raise an exception
|
86
|
+
# * `:install` - just install the gem
|
87
|
+
# The default is `:confirm`.
|
88
|
+
# @param on_conflict [:error,:warn,:ignore] What to do if bundler has
|
89
|
+
# already been run with a different Gemfile. Possible values:
|
90
|
+
# * `:error` - raise an exception
|
91
|
+
# * `:ignore` - just silently proceed without bundling again
|
92
|
+
# * `:warn` - print a warning and proceed without bundling again
|
93
|
+
# The default is `:error`.
|
94
|
+
# @param terminal [Toys::Utils::Terminal] Terminal to use (optional)
|
95
|
+
# @param input [IO] Input IO (optional, defaults to STDIN)
|
96
|
+
# @param output [IO] Output IO (optional, defaults to STDOUT)
|
97
|
+
# @param suppress_confirm [Boolean] Deprecated. Use `on_missing` instead.
|
98
|
+
# @param default_confirm [Boolean] Deprecated. Use `on_missing` instead.
|
83
99
|
#
|
84
|
-
def initialize(
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
@
|
92
|
-
@
|
93
|
-
|
100
|
+
def initialize(on_missing: nil,
|
101
|
+
on_conflict: nil,
|
102
|
+
terminal: nil,
|
103
|
+
input: nil,
|
104
|
+
output: nil,
|
105
|
+
suppress_confirm: nil,
|
106
|
+
default_confirm: nil)
|
107
|
+
@default_confirm = default_confirm || default_confirm.nil? ? true : false
|
108
|
+
@on_missing = on_missing ||
|
109
|
+
if suppress_confirm
|
110
|
+
@default_confirm ? :install : :error
|
111
|
+
else
|
112
|
+
:confirm
|
113
|
+
end
|
114
|
+
@on_conflict = on_conflict || :error
|
115
|
+
@terminal = terminal
|
116
|
+
@input = input || ::STDIN
|
117
|
+
@output = output || ::STDOUT
|
94
118
|
end
|
95
119
|
|
96
120
|
##
|
@@ -102,13 +126,56 @@ module Toys
|
|
102
126
|
# @return [void]
|
103
127
|
#
|
104
128
|
def activate(name, *requirements)
|
105
|
-
|
106
|
-
|
107
|
-
|
129
|
+
Gems.synchronize do
|
130
|
+
begin
|
131
|
+
gem(name, *requirements)
|
132
|
+
rescue ::Gem::LoadError => e
|
133
|
+
handle_activation_error(e, name, requirements)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Set up the bundle.
|
140
|
+
#
|
141
|
+
# @param groups [Array<String>] The groups to include in setup
|
142
|
+
# @param search_dirs [Array<String>] Directories to search for a Gemfile
|
143
|
+
# @return [void]
|
144
|
+
#
|
145
|
+
def bundle(groups: nil,
|
146
|
+
search_dirs: nil)
|
147
|
+
Gems.synchronize do
|
148
|
+
gemfile_path = find_gemfile(Array(search_dirs))
|
149
|
+
activate("bundler", "~> 2.1")
|
150
|
+
if configure_gemfile(gemfile_path)
|
151
|
+
setup_bundle(gemfile_path, groups || [])
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
@global_mutex = ::Monitor.new
|
157
|
+
|
158
|
+
## @private
|
159
|
+
def self.synchronize(&block)
|
160
|
+
@global_mutex.synchronize(&block)
|
108
161
|
end
|
109
162
|
|
110
163
|
private
|
111
164
|
|
165
|
+
def terminal
|
166
|
+
@terminal ||= begin
|
167
|
+
require "toys/utils/terminal"
|
168
|
+
Utils::Terminal.new(input: @input, output: @output)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def exec_util
|
173
|
+
@exec_util ||= begin
|
174
|
+
require "toys/utils/exec"
|
175
|
+
Utils::Exec.new
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
112
179
|
def handle_activation_error(error, name, requirements)
|
113
180
|
is_missing_spec =
|
114
181
|
if defined?(::Gem::MissingSpecError)
|
@@ -116,11 +183,11 @@ module Toys
|
|
116
183
|
else
|
117
184
|
error.message.include?("Could not find")
|
118
185
|
end
|
119
|
-
|
186
|
+
if !is_missing_spec || @on_missing == :error
|
120
187
|
report_error(name, requirements, error)
|
121
188
|
return
|
122
189
|
end
|
123
|
-
|
190
|
+
confirm_and_install_gem(name, requirements)
|
124
191
|
begin
|
125
192
|
gem(name, *requirements)
|
126
193
|
rescue ::Gem::LoadError => e
|
@@ -132,28 +199,16 @@ module Toys
|
|
132
199
|
"#{name.inspect}, #{requirements.map(&:inspect).join(', ')}"
|
133
200
|
end
|
134
201
|
|
135
|
-
def
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
default: @default_confirm)
|
202
|
+
def confirm_and_install_gem(name, requirements)
|
203
|
+
if @on_missing == :confirm
|
204
|
+
requirements_text = gem_requirements_text(name, requirements)
|
205
|
+
response = terminal.confirm("Gem needed: #{requirements_text}. Install? ",
|
206
|
+
default: @default_confirm)
|
207
|
+
unless response
|
208
|
+
raise InstallFailedError, "Canceled installation of needed gem: #{requirements_text}"
|
143
209
|
end
|
144
|
-
unless response
|
145
|
-
raise InstallFailedError, "Canceled installation of needed gem: #{requirements_text}"
|
146
|
-
end
|
147
|
-
perform_install(name, requirements)
|
148
|
-
end
|
149
|
-
|
150
|
-
def perform_install(name, requirements)
|
151
|
-
result = @terminal.spinner(leading_text: "Installing gem #{name}... ",
|
152
|
-
final_text: "Done.\n") do
|
153
|
-
@exec.exec(["gem", "install", name, "--version", requirements.join(",")],
|
154
|
-
out: :capture, err: :capture)
|
155
210
|
end
|
156
|
-
|
211
|
+
result = exec_util.exec(["gem", "install", name, "--version", requirements.join(",")])
|
157
212
|
if result.error?
|
158
213
|
raise InstallFailedError, "Failed to install gem #{name}"
|
159
214
|
end
|
@@ -167,6 +222,62 @@ module Toys
|
|
167
222
|
end
|
168
223
|
raise ActivationFailedError, err.message
|
169
224
|
end
|
225
|
+
|
226
|
+
def find_gemfile(search_dirs)
|
227
|
+
search_dirs.each do |dir|
|
228
|
+
gemfile_path = ::File.join(dir, "Gemfile")
|
229
|
+
return gemfile_path if ::File.readable?(gemfile_path)
|
230
|
+
end
|
231
|
+
raise GemfileNotFoundError, "Gemfile not found"
|
232
|
+
end
|
233
|
+
|
234
|
+
def configure_gemfile(gemfile_path)
|
235
|
+
old_path = ::ENV["BUNDLE_GEMFILE"]
|
236
|
+
if old_path && gemfile_path != old_path
|
237
|
+
case @on_conflict
|
238
|
+
when :warn
|
239
|
+
terminal.puts("Warning: could not set up bundler because it is already set up.", :red)
|
240
|
+
when :error
|
241
|
+
raise AlreadyBundledError, "Could not set up bundler because it is already set up"
|
242
|
+
end
|
243
|
+
return false
|
244
|
+
end
|
245
|
+
::ENV["BUNDLE_GEMFILE"] = gemfile_path
|
246
|
+
true
|
247
|
+
end
|
248
|
+
|
249
|
+
def setup_bundle(gemfile_path, groups)
|
250
|
+
require "bundler"
|
251
|
+
begin
|
252
|
+
::Bundler.setup(*groups)
|
253
|
+
rescue ::Bundler::GemNotFound
|
254
|
+
install_bundle(gemfile_path)
|
255
|
+
::Bundler.reset!
|
256
|
+
::Bundler.setup(*groups)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def permission_to_bundle?
|
261
|
+
case @on_missing
|
262
|
+
when :install
|
263
|
+
true
|
264
|
+
when :error
|
265
|
+
false
|
266
|
+
else
|
267
|
+
terminal.confirm("Your bundle is not complete. Install? ", default: @default_confirm)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def install_bundle(gemfile_path)
|
272
|
+
gemfile_dir = ::File.dirname(gemfile_path)
|
273
|
+
unless permission_to_bundle?
|
274
|
+
raise BundleNotInstalledError,
|
275
|
+
"Your bundle is not installed. Consider running" \
|
276
|
+
" `cd #{gemfile_dir} && bundle install`"
|
277
|
+
end
|
278
|
+
require "bundler/cli"
|
279
|
+
::Bundler::CLI.start(["install"])
|
280
|
+
end
|
170
281
|
end
|
171
282
|
end
|
172
283
|
end
|