toys-core 0.12.2 → 0.13.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 +22 -0
- data/LICENSE.md +1 -1
- data/README.md +4 -1
- data/docs/guide.md +1 -1
- data/lib/toys/acceptor.rb +10 -1
- data/lib/toys/arg_parser.rb +1 -0
- data/lib/toys/cli.rb +127 -107
- data/lib/toys/compat.rb +54 -3
- data/lib/toys/completion.rb +15 -5
- data/lib/toys/context.rb +22 -20
- data/lib/toys/core.rb +6 -2
- data/lib/toys/dsl/base.rb +2 -0
- data/lib/toys/dsl/flag.rb +23 -17
- data/lib/toys/dsl/flag_group.rb +11 -7
- data/lib/toys/dsl/positional_arg.rb +23 -13
- data/lib/toys/dsl/tool.rb +10 -6
- data/lib/toys/errors.rb +63 -8
- data/lib/toys/flag.rb +660 -651
- data/lib/toys/flag_group.rb +19 -6
- data/lib/toys/input_file.rb +9 -3
- data/lib/toys/loader.rb +129 -115
- data/lib/toys/middleware.rb +45 -21
- data/lib/toys/mixin.rb +8 -6
- data/lib/toys/positional_arg.rb +18 -17
- data/lib/toys/settings.rb +81 -67
- data/lib/toys/source_info.rb +33 -24
- data/lib/toys/standard_middleware/add_verbosity_flags.rb +2 -0
- data/lib/toys/standard_middleware/apply_config.rb +1 -0
- data/lib/toys/standard_middleware/handle_usage_errors.rb +1 -0
- data/lib/toys/standard_middleware/set_default_descriptions.rb +1 -0
- data/lib/toys/standard_middleware/show_help.rb +2 -0
- data/lib/toys/standard_middleware/show_root_version.rb +2 -0
- data/lib/toys/standard_mixins/bundler.rb +22 -14
- data/lib/toys/standard_mixins/exec.rb +31 -20
- data/lib/toys/standard_mixins/fileutils.rb +3 -1
- data/lib/toys/standard_mixins/gems.rb +21 -17
- data/lib/toys/standard_mixins/git_cache.rb +5 -7
- data/lib/toys/standard_mixins/highline.rb +8 -8
- data/lib/toys/standard_mixins/terminal.rb +5 -5
- data/lib/toys/standard_mixins/xdg.rb +5 -5
- data/lib/toys/template.rb +9 -7
- data/lib/toys/tool_definition.rb +209 -202
- data/lib/toys/utils/completion_engine.rb +7 -2
- data/lib/toys/utils/exec.rb +158 -127
- data/lib/toys/utils/gems.rb +81 -57
- data/lib/toys/utils/git_cache.rb +674 -45
- data/lib/toys/utils/help_text.rb +27 -3
- data/lib/toys/utils/terminal.rb +10 -2
- data/lib/toys/wrappable_string.rb +9 -2
- data/lib/toys-core.rb +14 -5
- metadata +4 -4
data/lib/toys/utils/exec.rb
CHANGED
@@ -280,7 +280,7 @@ module Toys
|
|
280
280
|
#
|
281
281
|
def exec_ruby(args, **opts, &block)
|
282
282
|
cmd = args.is_a?(::Array) ? [::RbConfig.ruby] + args : "#{::RbConfig.ruby} #{args}"
|
283
|
-
log_cmd =
|
283
|
+
log_cmd = "exec ruby: #{args.inspect}"
|
284
284
|
opts = {argv0: "ruby", log_cmd: log_cmd}.merge(opts)
|
285
285
|
exec(cmd, **opts, &block)
|
286
286
|
end
|
@@ -396,92 +396,6 @@ module Toys
|
|
396
396
|
exec(cmd, **opts, &block).exit_code
|
397
397
|
end
|
398
398
|
|
399
|
-
##
|
400
|
-
# An internal helper class storing the configuration of a subprocess invocation
|
401
|
-
# @private
|
402
|
-
#
|
403
|
-
class Opts
|
404
|
-
##
|
405
|
-
# Option keys that belong to exec configuration
|
406
|
-
# @private
|
407
|
-
#
|
408
|
-
CONFIG_KEYS = [
|
409
|
-
:argv0,
|
410
|
-
:background,
|
411
|
-
:cli,
|
412
|
-
:env,
|
413
|
-
:err,
|
414
|
-
:in,
|
415
|
-
:logger,
|
416
|
-
:log_cmd,
|
417
|
-
:log_level,
|
418
|
-
:name,
|
419
|
-
:out,
|
420
|
-
:result_callback,
|
421
|
-
].freeze
|
422
|
-
|
423
|
-
##
|
424
|
-
# Option keys that belong to spawn configuration
|
425
|
-
# @private
|
426
|
-
#
|
427
|
-
SPAWN_KEYS = [
|
428
|
-
:chdir,
|
429
|
-
:close_others,
|
430
|
-
:new_pgroup,
|
431
|
-
:pgroup,
|
432
|
-
:umask,
|
433
|
-
:unsetenv_others,
|
434
|
-
].freeze
|
435
|
-
|
436
|
-
## @private
|
437
|
-
def initialize(parent = nil)
|
438
|
-
if parent
|
439
|
-
@config_opts = ::Hash.new { |_h, k| parent.config_opts[k] }
|
440
|
-
@spawn_opts = ::Hash.new { |_h, k| parent.spawn_opts[k] }
|
441
|
-
elsif block_given?
|
442
|
-
@config_opts = ::Hash.new { |_h, k| yield k }
|
443
|
-
@spawn_opts = ::Hash.new { |_h, k| yield k }
|
444
|
-
else
|
445
|
-
@config_opts = {}
|
446
|
-
@spawn_opts = {}
|
447
|
-
end
|
448
|
-
end
|
449
|
-
|
450
|
-
## @private
|
451
|
-
def add(config)
|
452
|
-
config.each do |k, v|
|
453
|
-
if CONFIG_KEYS.include?(k)
|
454
|
-
@config_opts[k] = v
|
455
|
-
elsif SPAWN_KEYS.include?(k) || k.to_s.start_with?("rlimit_")
|
456
|
-
@spawn_opts[k] = v
|
457
|
-
else
|
458
|
-
raise ::ArgumentError, "Unknown key: #{k.inspect}"
|
459
|
-
end
|
460
|
-
end
|
461
|
-
self
|
462
|
-
end
|
463
|
-
|
464
|
-
## @private
|
465
|
-
def delete(*keys)
|
466
|
-
keys.each do |k|
|
467
|
-
if CONFIG_KEYS.include?(k)
|
468
|
-
@config_opts.delete(k)
|
469
|
-
elsif SPAWN_KEYS.include?(k) || k.to_s.start_with?("rlimit_")
|
470
|
-
@spawn_opts.delete(k)
|
471
|
-
else
|
472
|
-
raise ::ArgumentError, "Unknown key: #{k.inspect}"
|
473
|
-
end
|
474
|
-
end
|
475
|
-
self
|
476
|
-
end
|
477
|
-
|
478
|
-
## @private
|
479
|
-
attr_reader :config_opts
|
480
|
-
|
481
|
-
## @private
|
482
|
-
attr_reader :spawn_opts
|
483
|
-
end
|
484
|
-
|
485
399
|
##
|
486
400
|
# An object that controls a subprocess. This object is returned from an
|
487
401
|
# execution running in the background, or is yielded to a control block
|
@@ -490,28 +404,6 @@ module Toys
|
|
490
404
|
# send signals to the process, and get its result.
|
491
405
|
#
|
492
406
|
class Controller
|
493
|
-
## @private
|
494
|
-
def initialize(name, controller_streams, captures, pid, join_threads,
|
495
|
-
result_callback, mutex)
|
496
|
-
@name = name
|
497
|
-
@in = controller_streams[:in]
|
498
|
-
@out = controller_streams[:out]
|
499
|
-
@err = controller_streams[:err]
|
500
|
-
@captures = captures
|
501
|
-
@pid = @exception = @wait_thread = nil
|
502
|
-
case pid
|
503
|
-
when ::Integer
|
504
|
-
@pid = pid
|
505
|
-
@wait_thread = ::Process.detach(pid)
|
506
|
-
when ::Exception
|
507
|
-
@exception = pid
|
508
|
-
end
|
509
|
-
@join_threads = join_threads
|
510
|
-
@result_callback = result_callback
|
511
|
-
@mutex = mutex
|
512
|
-
@result = nil
|
513
|
-
end
|
514
|
-
|
515
407
|
##
|
516
408
|
# The subcommand's name.
|
517
409
|
# @return [Object]
|
@@ -746,8 +638,33 @@ module Toys
|
|
746
638
|
end
|
747
639
|
end
|
748
640
|
|
641
|
+
##
|
642
|
+
# @private
|
643
|
+
#
|
644
|
+
def initialize(name, controller_streams, captures, pid, join_threads,
|
645
|
+
result_callback, mutex)
|
646
|
+
@name = name
|
647
|
+
@in = controller_streams[:in]
|
648
|
+
@out = controller_streams[:out]
|
649
|
+
@err = controller_streams[:err]
|
650
|
+
@captures = captures
|
651
|
+
@pid = @exception = @wait_thread = nil
|
652
|
+
case pid
|
653
|
+
when ::Integer
|
654
|
+
@pid = pid
|
655
|
+
@wait_thread = ::Process.detach(pid)
|
656
|
+
when ::Exception
|
657
|
+
@exception = pid
|
658
|
+
end
|
659
|
+
@join_threads = join_threads
|
660
|
+
@result_callback = result_callback
|
661
|
+
@mutex = mutex
|
662
|
+
@result = nil
|
663
|
+
end
|
664
|
+
|
749
665
|
##
|
750
666
|
# Close the controller's streams.
|
667
|
+
#
|
751
668
|
# @private
|
752
669
|
#
|
753
670
|
def close_streams(which)
|
@@ -799,15 +716,6 @@ module Toys
|
|
799
716
|
# return the numeric signal code.
|
800
717
|
#
|
801
718
|
class Result
|
802
|
-
## @private
|
803
|
-
def initialize(name, out, err, status, exception)
|
804
|
-
@name = name
|
805
|
-
@captured_out = out
|
806
|
-
@captured_err = err
|
807
|
-
@status = status
|
808
|
-
@exception = exception
|
809
|
-
end
|
810
|
-
|
811
719
|
##
|
812
720
|
# The subcommand's name.
|
813
721
|
#
|
@@ -928,13 +836,129 @@ module Toys
|
|
928
836
|
code = exit_code
|
929
837
|
!code.nil? && !code.zero?
|
930
838
|
end
|
839
|
+
|
840
|
+
##
|
841
|
+
# @private
|
842
|
+
#
|
843
|
+
def initialize(name, out, err, status, exception)
|
844
|
+
@name = name
|
845
|
+
@captured_out = out
|
846
|
+
@captured_err = err
|
847
|
+
@status = status
|
848
|
+
@exception = exception
|
849
|
+
end
|
850
|
+
end
|
851
|
+
|
852
|
+
private
|
853
|
+
|
854
|
+
##
|
855
|
+
# An internal helper class storing the configuration of a subprocess invocation
|
856
|
+
#
|
857
|
+
# @private
|
858
|
+
#
|
859
|
+
class Opts
|
860
|
+
##
|
861
|
+
# Option keys that belong to exec configuration
|
862
|
+
#
|
863
|
+
# @private
|
864
|
+
#
|
865
|
+
CONFIG_KEYS = [
|
866
|
+
:argv0,
|
867
|
+
:background,
|
868
|
+
:cli,
|
869
|
+
:env,
|
870
|
+
:err,
|
871
|
+
:in,
|
872
|
+
:logger,
|
873
|
+
:log_cmd,
|
874
|
+
:log_level,
|
875
|
+
:name,
|
876
|
+
:out,
|
877
|
+
:result_callback,
|
878
|
+
].freeze
|
879
|
+
|
880
|
+
##
|
881
|
+
# Option keys that belong to spawn configuration
|
882
|
+
#
|
883
|
+
# @private
|
884
|
+
#
|
885
|
+
SPAWN_KEYS = [
|
886
|
+
:chdir,
|
887
|
+
:close_others,
|
888
|
+
:new_pgroup,
|
889
|
+
:pgroup,
|
890
|
+
:umask,
|
891
|
+
:unsetenv_others,
|
892
|
+
].freeze
|
893
|
+
|
894
|
+
##
|
895
|
+
# @private
|
896
|
+
#
|
897
|
+
def initialize(parent = nil)
|
898
|
+
if parent
|
899
|
+
@config_opts = ::Hash.new { |_h, k| parent.config_opts[k] }
|
900
|
+
@spawn_opts = ::Hash.new { |_h, k| parent.spawn_opts[k] }
|
901
|
+
elsif block_given?
|
902
|
+
@config_opts = ::Hash.new { |_h, k| yield k }
|
903
|
+
@spawn_opts = ::Hash.new { |_h, k| yield k }
|
904
|
+
else
|
905
|
+
@config_opts = {}
|
906
|
+
@spawn_opts = {}
|
907
|
+
end
|
908
|
+
end
|
909
|
+
|
910
|
+
##
|
911
|
+
# @private
|
912
|
+
#
|
913
|
+
def add(config)
|
914
|
+
config.each do |k, v|
|
915
|
+
if CONFIG_KEYS.include?(k)
|
916
|
+
@config_opts[k] = v
|
917
|
+
elsif SPAWN_KEYS.include?(k) || k.to_s.start_with?("rlimit_")
|
918
|
+
@spawn_opts[k] = v
|
919
|
+
else
|
920
|
+
raise ::ArgumentError, "Unknown key: #{k.inspect}"
|
921
|
+
end
|
922
|
+
end
|
923
|
+
self
|
924
|
+
end
|
925
|
+
|
926
|
+
##
|
927
|
+
# @private
|
928
|
+
#
|
929
|
+
def delete(*keys)
|
930
|
+
keys.each do |k|
|
931
|
+
if CONFIG_KEYS.include?(k)
|
932
|
+
@config_opts.delete(k)
|
933
|
+
elsif SPAWN_KEYS.include?(k) || k.to_s.start_with?("rlimit_")
|
934
|
+
@spawn_opts.delete(k)
|
935
|
+
else
|
936
|
+
raise ::ArgumentError, "Unknown key: #{k.inspect}"
|
937
|
+
end
|
938
|
+
end
|
939
|
+
self
|
940
|
+
end
|
941
|
+
|
942
|
+
##
|
943
|
+
# @private
|
944
|
+
#
|
945
|
+
attr_reader :config_opts
|
946
|
+
|
947
|
+
##
|
948
|
+
# @private
|
949
|
+
#
|
950
|
+
attr_reader :spawn_opts
|
931
951
|
end
|
932
952
|
|
933
953
|
##
|
934
954
|
# An object that manages the execution of a subcommand
|
955
|
+
#
|
935
956
|
# @private
|
936
957
|
#
|
937
958
|
class Executor
|
959
|
+
##
|
960
|
+
# @private
|
961
|
+
#
|
938
962
|
def initialize(exec_opts, spawn_cmd, block)
|
939
963
|
@fork_func = spawn_cmd.respond_to?(:call) ? spawn_cmd : nil
|
940
964
|
@spawn_cmd = spawn_cmd.respond_to?(:call) ? nil : spawn_cmd
|
@@ -950,6 +974,9 @@ module Toys
|
|
950
974
|
@mutex = ::Mutex.new
|
951
975
|
end
|
952
976
|
|
977
|
+
##
|
978
|
+
# @private
|
979
|
+
#
|
953
980
|
def execute
|
954
981
|
setup_in_stream
|
955
982
|
setup_out_stream(:out)
|
@@ -970,17 +997,23 @@ module Toys
|
|
970
997
|
def log_command
|
971
998
|
logger = @config_opts[:logger]
|
972
999
|
if logger && @config_opts[:log_level] != false
|
973
|
-
cmd_str = @config_opts[:log_cmd] || default_log_str
|
1000
|
+
cmd_str = @config_opts[:log_cmd] || default_log_str
|
974
1001
|
logger.add(@config_opts[:log_level] || ::Logger::INFO, cmd_str) if cmd_str
|
975
1002
|
end
|
976
1003
|
end
|
977
1004
|
|
978
|
-
def default_log_str
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
1005
|
+
def default_log_str
|
1006
|
+
if @fork_func
|
1007
|
+
"exec proc: #{@fork_func.inspect}"
|
1008
|
+
elsif @spawn_cmd
|
1009
|
+
if @spawn_cmd.size == 1 && @spawn_cmd.first.is_a?(::String)
|
1010
|
+
"exec sh: #{@spawn_cmd.first.inspect}"
|
1011
|
+
else
|
1012
|
+
cmd_binary = @spawn_cmd.first
|
1013
|
+
cmd_binary = cmd_binary.first if cmd_binary.is_a?(::Array)
|
1014
|
+
"exec: #{([cmd_binary] + @spawn_cmd[1..-1]).inspect}"
|
1015
|
+
end
|
1016
|
+
end
|
984
1017
|
end
|
985
1018
|
|
986
1019
|
def start_with_controller
|
@@ -1311,8 +1344,6 @@ module Toys
|
|
1311
1344
|
end
|
1312
1345
|
end
|
1313
1346
|
|
1314
|
-
private
|
1315
|
-
|
1316
1347
|
def canonical_binary_spec(cmd, exec_opts)
|
1317
1348
|
config_argv0 = exec_opts.config_opts[:argv0]
|
1318
1349
|
return cmd.to_s if !config_argv0 && !cmd.is_a?(::Array)
|
data/lib/toys/utils/gems.rb
CHANGED
@@ -188,15 +188,16 @@ module Toys
|
|
188
188
|
gemfile_path = ::File.absolute_path(gemfile_path)
|
189
189
|
Gems.synchronize do
|
190
190
|
if configure_gemfile(gemfile_path)
|
191
|
-
activate("bundler", "~> 2.
|
191
|
+
activate("bundler", "~> 2.2")
|
192
192
|
require "bundler"
|
193
|
-
|
194
|
-
setup_bundle(gemfile_path, lockfile_path, groups: groups, retries: retries)
|
193
|
+
setup_bundle(gemfile_path, groups: groups, retries: retries)
|
195
194
|
end
|
196
195
|
end
|
197
196
|
end
|
198
197
|
|
198
|
+
##
|
199
199
|
# @private
|
200
|
+
#
|
200
201
|
def self.find_gemfile(search_dir, gemfile_names: nil)
|
201
202
|
gemfile_names ||= DEFAULT_GEMFILE_NAMES
|
202
203
|
Array(gemfile_names).each do |file|
|
@@ -208,7 +209,9 @@ module Toys
|
|
208
209
|
|
209
210
|
@global_mutex = ::Monitor.new
|
210
211
|
|
212
|
+
##
|
211
213
|
# @private
|
214
|
+
#
|
212
215
|
def self.synchronize(&block)
|
213
216
|
@global_mutex.synchronize(&block)
|
214
217
|
end
|
@@ -255,8 +258,7 @@ module Toys
|
|
255
258
|
def confirm_and_install_gem(name, requirements)
|
256
259
|
if @on_missing == :confirm
|
257
260
|
requirements_text = gem_requirements_text(name, requirements)
|
258
|
-
response = terminal.confirm("Gem needed: #{requirements_text}. Install? ",
|
259
|
-
default: @default_confirm)
|
261
|
+
response = terminal.confirm("Gem needed: #{requirements_text}. Install? ", default: @default_confirm)
|
260
262
|
unless response
|
261
263
|
raise InstallFailedError, "Canceled installation of needed gem: #{requirements_text}"
|
262
264
|
end
|
@@ -301,71 +303,92 @@ module Toys
|
|
301
303
|
end
|
302
304
|
end
|
303
305
|
|
304
|
-
def setup_bundle(gemfile_path,
|
306
|
+
def setup_bundle(gemfile_path, groups: nil, retries: nil)
|
307
|
+
check_gemfile_compatibility(gemfile_path)
|
305
308
|
groups = Array(groups)
|
306
|
-
|
309
|
+
modified_gemfile_path = create_modified_gemfile(gemfile_path)
|
307
310
|
begin
|
308
|
-
|
309
|
-
::Bundler.ui.silence { ::Bundler.setup(*groups) }
|
311
|
+
attempt_setup_bundle(modified_gemfile_path, groups)
|
310
312
|
rescue ::Bundler::GemNotFound, ::Bundler::VersionConflict
|
311
|
-
restore_toys_libs
|
312
|
-
install_bundle(gemfile_path, retries: retries)
|
313
|
-
old_lockfile_contents = save_old_lockfile(lockfile_path)
|
314
313
|
::Bundler.reset!
|
315
|
-
|
316
|
-
|
314
|
+
restore_toys_libs
|
315
|
+
install_bundle(modified_gemfile_path, retries: retries)
|
316
|
+
attempt_setup_bundle(modified_gemfile_path, groups)
|
317
|
+
ensure
|
318
|
+
delete_modified_gemfile(modified_gemfile_path)
|
319
|
+
::ENV["BUNDLE_GEMFILE"] = gemfile_path
|
317
320
|
end
|
318
321
|
restore_toys_libs
|
319
|
-
ensure
|
320
|
-
restore_old_lockfile(lockfile_path, old_lockfile_contents)
|
321
322
|
end
|
322
323
|
|
323
|
-
def
|
324
|
-
|
325
|
-
::
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
::File.open(lockfile_path, "w") do |file|
|
331
|
-
file.write(contents)
|
324
|
+
def attempt_setup_bundle(modified_gemfile_path, groups)
|
325
|
+
::ENV["BUNDLE_GEMFILE"] = modified_gemfile_path
|
326
|
+
::Bundler.configure
|
327
|
+
::Bundler.settings.temporary({gemfile: modified_gemfile_path}) do
|
328
|
+
::Bundler.ui.silence do
|
329
|
+
::Bundler.setup(*groups)
|
330
|
+
end
|
332
331
|
end
|
333
332
|
end
|
334
333
|
|
335
|
-
def
|
334
|
+
def check_gemfile_compatibility(gemfile_path)
|
336
335
|
::Bundler.configure
|
337
336
|
builder = ::Bundler::Dsl.new
|
338
337
|
builder.eval_gemfile(gemfile_path)
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
add_gem_to_definition(builder, "toys-core")
|
343
|
-
if removed_toys || ::Toys.const_defined?(:VERSION)
|
344
|
-
add_gem_to_definition(builder, "toys")
|
345
|
-
toys_gems << "toys"
|
346
|
-
end
|
347
|
-
definition = builder.to_definition(lockfile_path, { gems: toys_gems })
|
348
|
-
::Bundler.instance_variable_set(:@definition, definition)
|
338
|
+
check_gemfile_gem_compatibility(builder, "toys-core")
|
339
|
+
check_gemfile_gem_compatibility(builder, "toys")
|
340
|
+
::Bundler.reset!
|
349
341
|
end
|
350
342
|
|
351
|
-
def
|
343
|
+
def check_gemfile_gem_compatibility(builder, name)
|
352
344
|
existing_dep = builder.dependencies.find { |dep| dep.name == name }
|
353
|
-
|
354
|
-
unless existing_dep.requirement.satisfied_by?(::Gem::Version.new(::Toys::Core::VERSION))
|
345
|
+
if existing_dep && !existing_dep.requirement.satisfied_by?(::Gem::Version.new(::Toys::Core::VERSION))
|
355
346
|
raise IncompatibleToysError,
|
356
347
|
"The bundle lists #{name} #{existing_dep.requirement} as a dependency, which is" \
|
357
|
-
" incompatible with the current version #{::Toys::Core::VERSION}."
|
348
|
+
" incompatible with the current toys version #{::Toys::Core::VERSION}."
|
358
349
|
end
|
359
|
-
builder.dependencies.delete(existing_dep)
|
360
|
-
true
|
361
350
|
end
|
362
351
|
|
363
|
-
def
|
364
|
-
|
365
|
-
|
352
|
+
def create_modified_gemfile(gemfile_path)
|
353
|
+
dir = ::File.dirname(gemfile_path)
|
354
|
+
modified_gemfile_path = loop do
|
355
|
+
timestamp = ::Time.now.strftime("%Y%m%d%H%M%S")
|
356
|
+
uniquifier = rand(3_656_158_440_062_976).to_s(36) # 10 digits in base 36
|
357
|
+
path = ::File.join(dir, ".toys-tmp-gemfile-#{timestamp}-#{uniquifier}")
|
358
|
+
break path unless ::File.exist?(path)
|
359
|
+
end
|
360
|
+
::File.open(modified_gemfile_path, "w") do |file|
|
361
|
+
modified_gemfile_content(gemfile_path).each do |line|
|
362
|
+
file.puts(line)
|
363
|
+
end
|
366
364
|
end
|
367
|
-
|
368
|
-
|
365
|
+
lockfile_path = find_lockfile_path(gemfile_path)
|
366
|
+
modified_lockfile_path = find_lockfile_path(modified_gemfile_path)
|
367
|
+
if ::File.readable?(lockfile_path)
|
368
|
+
lockfile_content = ::File.read(lockfile_path)
|
369
|
+
::File.open(modified_lockfile_path, "w") { |file| file.write(lockfile_content) }
|
370
|
+
end
|
371
|
+
modified_gemfile_path
|
372
|
+
end
|
373
|
+
|
374
|
+
def modified_gemfile_content(gemfile_path)
|
375
|
+
is_running_toys = ::Toys.const_defined?(:VERSION)
|
376
|
+
content = [::File.read(gemfile_path)]
|
377
|
+
content << "has_toys_dep = dependencies.any? { |dep| dep.name == 'toys' }" unless is_running_toys
|
378
|
+
content << "dependencies.delete_if { |dep| dep.name == 'toys-core' || dep.name == 'toys' }"
|
379
|
+
repo_root = ::File.dirname(::File.dirname(::Toys::CORE_LIB_PATH)) if ::ENV["TOYS_DEV"]
|
380
|
+
path = repo_root ? ::File.join(repo_root, "toys-core") : nil
|
381
|
+
content << "gem 'toys-core', #{::Toys::Core::VERSION.inspect}, path: #{path.inspect}"
|
382
|
+
path = repo_root ? ::File.join(repo_root, "toys") : nil
|
383
|
+
guard = is_running_toys ? "" : " if has_toys_dep"
|
384
|
+
content << "gem 'toys', #{::Toys::Core::VERSION.inspect}, path: #{path.inspect}#{guard}"
|
385
|
+
content
|
386
|
+
end
|
387
|
+
|
388
|
+
def delete_modified_gemfile(modified_gemfile_path)
|
389
|
+
::File.delete(modified_gemfile_path) if ::File.exist?(modified_gemfile_path)
|
390
|
+
modified_lockfile_path = find_lockfile_path(modified_gemfile_path)
|
391
|
+
::File.delete(modified_lockfile_path) if ::File.exist?(modified_lockfile_path)
|
369
392
|
end
|
370
393
|
|
371
394
|
def restore_toys_libs
|
@@ -384,8 +407,7 @@ module Toys
|
|
384
407
|
when :error
|
385
408
|
false
|
386
409
|
else
|
387
|
-
terminal.confirm("Your bundle requires additional gems. Install? ",
|
388
|
-
default: @default_confirm)
|
410
|
+
terminal.confirm("Your bundle requires additional gems. Install? ", default: @default_confirm)
|
389
411
|
end
|
390
412
|
end
|
391
413
|
|
@@ -393,17 +415,19 @@ module Toys
|
|
393
415
|
gemfile_dir = ::File.dirname(gemfile_path)
|
394
416
|
unless permission_to_bundle?
|
395
417
|
raise BundleNotInstalledError,
|
396
|
-
"Your bundle is not installed. Consider running"
|
397
|
-
" `cd #{gemfile_dir} && bundle install`"
|
418
|
+
"Your bundle is not installed. Consider running `cd #{gemfile_dir} && bundle install`"
|
398
419
|
end
|
399
420
|
retries = retries.to_i
|
400
|
-
args =
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
421
|
+
args = ["--gemfile=#{gemfile_path}"]
|
422
|
+
args << "--retry=#{retries}" if retries.positive?
|
423
|
+
bundler_bin = ::Gem.bin_path("bundler", "bundle", ::Bundler::VERSION)
|
424
|
+
result = exec_util.exec_ruby([bundler_bin, "install"] + args)
|
425
|
+
if result.error?
|
405
426
|
terminal.puts("Failed to install. Trying update...")
|
406
|
-
|
427
|
+
result = exec_util.exec_ruby([bundler_bin, "update"] + args)
|
428
|
+
unless result.success?
|
429
|
+
raise ::Bundler::InstallError, "Failed to install or update bundle: #{gemfile_path}"
|
430
|
+
end
|
407
431
|
end
|
408
432
|
end
|
409
433
|
end
|