toys-core 0.12.2 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|