squared 0.7.1 → 0.7.3

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.
@@ -192,7 +192,7 @@ module Squared
192
192
 
193
193
  subtasks({
194
194
  'outdated' => %i[major minor patch].freeze,
195
- 'ruby' => %i[file script version].freeze,
195
+ 'ruby' => %i[file script version reshim].freeze,
196
196
  'gem' => %i[install uninstall outdated update pristine build push exec command].freeze,
197
197
  'bundle' => %i[config install update cache exec reinstall command].freeze,
198
198
  'rake' => nil,
@@ -202,6 +202,7 @@ module Squared
202
202
  })
203
203
 
204
204
  attr_reader :gemdir
205
+ attr_accessor :autodetect
205
206
 
206
207
  def initialize(*, autodetect: false, steep: 'Steepfile', rubocop: '.rubocop.yml', asdf: 'ruby', **kwargs)
207
208
  super
@@ -213,12 +214,13 @@ module Squared
213
214
  initialize_env(**kwargs)
214
215
  end
215
216
  dependfile_set GEMFILE
217
+ serve_set kwargs[:serve]
216
218
  gemfile_set kwargs[:gemspec]
217
- @autodetect = autodetect
219
+ self.autodetect = autodetect
218
220
  @steepfile = basepath! steep if steep
219
221
  @rubocopfile = Pathname.new(rubocop).realpath rescue basepath!(Dir.home, '.rubocop.yml') if rubocop
220
222
  @rubygems = kwargs.fetch(:rubygems, 0)
221
- return unless rakefile && @output[0].nil? && @copy.nil? && !version && !@autodetect
223
+ return unless rakefile && @output[0].nil? && @copy.nil? && !version && !self.autodetect
222
224
 
223
225
  begin
224
226
  File.foreach(rakefile) do |line|
@@ -458,9 +460,10 @@ module Squared
458
460
  bundle(flag, opts: args.to_a, banner: flag == :exec ? verbose? : true)
459
461
  end
460
462
  when :reinstall
461
- format_desc action, flag, 'f/orce?,opts*'
463
+ format_desc action, flag, 'f/orce?,l/ocal?,opts*'
462
464
  task flag do |_, args|
463
465
  opts = args.to_a
466
+ opts << 'local' if has_value!(opts, 'l')
464
467
  opts << 'redownload' if has_value!(opts, 'f', 'force')
465
468
  if (lock = basepath!('Gemfile.lock'))
466
469
  config = basepath '.bundle', 'config'
@@ -526,145 +529,132 @@ module Squared
526
529
  ruby(flag, opts: args.to_a, command: command)
527
530
  end
528
531
  when :version
529
- format_desc action, flag
530
- task flag do
531
- pwd_set do
532
- out = []
533
- order = { 'rbenv' => -1, 'rvm' => -1, 'chruby' => -1, 'mise' => -1 }
534
- ENV.fetch('PATH', '').split(':').each_with_index do |val, index|
535
- order.each_key do |key|
536
- next unless val.match?(%r{[/.]#{key}/})
537
-
538
- order[key] = index
539
- break
532
+ format_desc action, flag, 'local?,alias?'
533
+ task flag, [:local, :name] do |_, args|
534
+ ver = %w[.tool-versions .ruby-version]
535
+ mise = %w[mise.local.toml mise.toml]
536
+ s = args.local
537
+ if s && (%w[system latest].include?(s) || SEM_VER.match?(s) || s.start_with?(/(path|ref):/))
538
+ rbvm = exist?(ver.last) && !exist?(ver.first)
539
+ case vmname
540
+ when nil
541
+ print_error('no version manager detected', subject: name)
542
+ next
543
+ when 'asdf'
544
+ unless rbvm
545
+ asdf(:set, **{ name: args.name, version: s, banner: verbose? }.compact)
546
+ next
540
547
  end
541
- end
542
- if @asdf
543
- [File.join(ENV.fetch('ASDF_DATA_DIR', '$HOME/.asdf'), "installs/#{@asdf.first}")]
544
- else
545
- [
546
- "#{ENV.fetch('RBENV_ROOT', '$HOME/.rbenv')}/bin/rbenv",
547
- '$HOME/.rvm/bin/rvm',
548
- '$HOME/.local/bin/mise',
549
- '/usr/bin/rbenv',
550
- '/usr/bin/mise',
551
- '/usr/local/rvm/bin/rvm',
552
- '/usr/share/rvm/bin/rvm',
553
- '/usr/local/share/chruby/chruby.sh'
554
- ]
555
- .sort do |a, b|
556
- c = -1
557
- d = -1
558
- order.each do |key, val|
559
- pat = %r{/\.?#{key}}
560
- c = val if a.match?(pat)
561
- d = val if b.match?(pat)
562
- end
563
- if c == d
564
- 0
565
- elsif c == -1
566
- 1
567
- elsif d == -1
568
- -1
569
- else
570
- c < d ? -1 : 1
571
- end
548
+ when 'mise'
549
+ if mise.none? { |val| exist?(val) } && rbvm.call
550
+ save.call
551
+ else
552
+ cmd = session 'mise', 'use'
553
+ cmd << '--env local' if exist?(mise.first)
554
+ cmd << "#{args.name || 'ruby'}@#{s}"
555
+ run(banner: verbose?)
556
+ next
572
557
  end
573
- .push('')
574
558
  end
575
- .each do |val|
576
- next unless val.empty? || File.exist?(val.sub('$HOME', Dir.home))
577
-
578
- trim = ->(s) { s[/^\D+\d+\.\d+(?:\.\S+)?/, 0].sub(/^([a-z]+)-/i, '\1 ') }
579
- ver = %w[.tool-versions .ruby-version]
580
- out << trim.call(case (cmd = File.basename(val))
581
- when 'rvm'
582
- ver.shift
583
- `rvm current`[/^\S+/, 0]
584
- when 'rbenv'
585
- ver.shift
586
- name = `rbenv version-name`
587
- name.match?(SEM_VER) ? "ruby #{name}" : name
588
- when 'chruby.sh'
589
- ver.shift
590
- chruby = session_output 'source', val
591
- `#{chruby.with('ruby --version')}`
592
- when 'mise'
593
- data = parse_json(`mise ls ruby --json`, kind: Array)
594
- data = data.find { |item| item['active'] } || data.first
595
- "ruby #{data['version']}"
596
- else
597
- if @asdf
598
- cmd = 'asdf'
599
- if @@asdf.config && File.exist?(@@asdf.config)
600
- pat = /legacy_version_file\s+=\s+(yes|no)/
601
- ver.pop unless File.read(@@asdf.config)[pat, 1] == 'yes'
602
- else
603
- ver.pop
604
- end
605
- opt = [@asdf.first]
606
- opt.unshift('--no-header') unless @@asdf.version == 15
607
- cur = `asdf current #{opt.join(' ')}`
608
- if cur.match?(/\sfalse\b/)
609
- `ruby --version`
610
- else
611
- cur[/^\S+\s+\S+/, 0].sub(/\s+/, ' ')
612
- end
613
- else
614
- ver = nil
615
- `ruby --version`
559
+ File.write(basepath(ver.last), "#{s}\n") if SEM_VER.match?(s)
560
+ next
561
+ end
562
+ pwd_set do
563
+ out = []
564
+ tool = args.name || (args.local && !SEM_VER.match?(args.local) ? args.local : 'ruby')
565
+ trim = ->(s) { s[/^\D+\d+\.\d+(?:\.\S+)?/, 0].sub(/^([a-z]+)-/i, '\1 ') }
566
+ out << trim.call(case (vm, bin = vmname(bin: true))
567
+ when 'rvm'
568
+ ver.shift
569
+ `rvm current`[/^\S+/, 0]
570
+ when 'rbenv'
571
+ ver.shift
572
+ name = `rbenv version-name`
573
+ (name =~ SEM_VER) == 0 ? "ruby #{name}" : name
574
+ when 'chruby'
575
+ ver.shift
576
+ chruby = session_output 'source', bin
577
+ `#{chruby.with('ruby --version')}`
578
+ when 'mise'
579
+ data = parse_json(`mise ls #{tool} --json`, kind: Array)
580
+ cur = `mise current #{tool}`.split.find do |val|
581
+ data.any? do |item|
582
+ item['version'] == val && item['installed'] && item['active']
616
583
  end
617
- end)
618
- break if workspace.windows?
619
-
620
- unless val.empty?
621
- out << trim.call(case cmd
622
- when 'chruby.sh'
584
+ end
585
+ "ruby #{cur || data.first['version']}"
586
+ when 'asdf'
587
+ if @@asdf.config && File.exist?(@@asdf.config)
588
+ pat = /legacy_version_file\s+=\s+(yes|no)/
589
+ ver.pop unless File.read(@@asdf.config)[pat, 1] == 'yes'
590
+ else
591
+ ver.pop
592
+ end
593
+ opt = [@asdf.first]
594
+ opt.unshift('--no-header') unless @@asdf.version == 15
595
+ cur = `asdf current #{opt.join(' ')}`
596
+ if cur.match?(/\sfalse\b/)
597
+ `ruby --version`
598
+ else
599
+ cur[/^\S+\s+\S+/, 0].sub(/\s+/, ' ')
600
+ end
601
+ else
602
+ ver = nil
603
+ `ruby --version`
604
+ end)
605
+ unless workspace.windows?
606
+ if vm
607
+ out << trim.call(case vm
608
+ when 'chruby'
623
609
  `#{chruby.with('chruby --version')}`.sub(':', '')
624
610
  when 'asdf'
625
611
  "asdf #{`asdf version`.delete_prefix('v')}"
626
612
  when 'mise'
627
- data = parse_json `mise version --json`
628
- "mise #{data['latest']}"
613
+ "mise #{parse_json(`mise version --json`, key: 'latest')}"
629
614
  else
630
- `#{cmd} --version`
615
+ `#{vm} --version`
631
616
  end)
632
617
  end
633
618
  begin
634
- out << ('which %s' % case cmd
619
+ out << ('which %s' % case vm
635
620
  when 'rbenv'
636
- `rbenv which ruby`
637
- when 'chruby.sh'
621
+ `rbenv which #{tool}`
622
+ when 'chruby'
638
623
  `#{chruby.with('which ruby')}`
639
624
  when 'asdf'
640
625
  `asdf which #{@asdf.first}`
641
626
  when 'mise'
642
- `mise which ruby`
627
+ `mise which #{tool}`
643
628
  else
644
- `which ruby`
629
+ `which #{tool}`
645
630
  end)
646
631
  rescue => e
647
632
  log.debug e
648
633
  end
649
634
  if ver
635
+ ver = mise + ver if vm == 'mise'
650
636
  catch :found do
651
637
  path.ascend do |dir|
652
638
  ver.filter { |val| dir.join(val).exist? }.each do |val|
653
639
  dir += val
654
- hint = File.read(dir)
655
- .lines
656
- .map { |s| s.sub(/#.*$/, '').strip }
657
- .reject(&:empty?)
658
- .join(', ')
640
+ file = File.read(dir)
641
+ hint = if val.include?('mise')
642
+ line = file[/^\s*#{tool}\s*=\s*\[?(.+?)\]?\s*$/, 1]
643
+ line&.gsub(/["']/, '')
644
+ else
645
+ file.lines
646
+ .map { |line| line.sub(/#.*$/, '').strip }
647
+ .reject(&:empty?)
648
+ .join(', ')
649
+ end
659
650
  out << message("found #{dir}", hint: hint)
660
- throw :found if hint.include?(out.first[/^ruby (.+)$/, 1])
651
+ throw :found if hint&.include?(out.first[/^(?:j|truffle)?ruby ([\d.]+)/, 1])
661
652
  rescue
662
653
  nil
663
654
  end
664
655
  end
665
656
  end
666
657
  end
667
- break
668
658
  end
669
659
  out.map!(&:split)
670
660
  pad = as_a(out, :first, :size).max
@@ -672,6 +662,21 @@ module Squared
672
662
  puts(out.map { |line| '%*s %s' % [pad, line.first, line[1..-1].join(' ')] })
673
663
  end
674
664
  end
665
+ when :reshim
666
+ format_desc action, flag, 'name?'
667
+ task flag, [:name] do |_, args|
668
+ case vmname
669
+ when 'rbenv'
670
+ cmd = session 'rbenv', 'rehash'
671
+ when 'asdf'
672
+ asdf(:reshim, **{ name: args.name, banner: verbose? }.compact)
673
+ when 'mise'
674
+ cmd = session('mise', 'reshim', args.name || 'ruby')
675
+ else
676
+ print_error('not supported by version manager', subject: args.name)
677
+ end
678
+ success?(run(banner: verbose?), verbose?) if cmd
679
+ end
675
680
  end
676
681
  end
677
682
  end
@@ -904,7 +909,7 @@ module Squared
904
909
  items.map(&:last)
905
910
  end
906
911
  if dryrun
907
- print_run bundle_output("update --#{flag}", *gems.quote!), false
912
+ print_run bundle_output("update --#{flag}", *gems.quote!(escape: true)), false
908
913
  else
909
914
  bundle(:update, *gems, opts: [flag.to_s])
910
915
  end
@@ -1149,7 +1154,7 @@ module Squared
1149
1154
  end
1150
1155
  end
1151
1156
  if filter[:dryrun]
1152
- print_run gem_output('update -f', *update.quote!), false
1157
+ print_run gem_output('update -f', *update.quote!(escape: true)), false
1153
1158
  else
1154
1159
  gem(:update, *update, opts: opts)
1155
1160
  end
@@ -1167,6 +1172,7 @@ module Squared
1167
1172
  when :dependency, :environment, :list, :search, :specification, :which
1168
1173
  op.concat(args)
1169
1174
  end
1175
+ ia = op.remove(':')
1170
1176
  op.each do |opt|
1171
1177
  if gems && !opt.start_with?('-') && !opt.match?(GEMNAME)
1172
1178
  op.errors << opt
@@ -1224,11 +1230,11 @@ module Squared
1224
1230
  if op.arg?('system')
1225
1231
  op.add_first(quote: false) { |val| val if val.match?(SEM_VER) }
1226
1232
  else
1227
- op.append
1233
+ op.append(escape: true)
1228
1234
  end
1229
1235
  when :install, :uninstall, :pristine
1230
1236
  if flag == :install
1231
- post = if op.remove(':')
1237
+ post = if ia
1232
1238
  op.concat(args)
1233
1239
  readline('Enter command [args]', force: true)
1234
1240
  elsif op.empty?
@@ -1237,6 +1243,25 @@ module Squared
1237
1243
  elsif !args.empty?
1238
1244
  args.join(' ')
1239
1245
  end
1246
+ elsif ia
1247
+ name = op.shift || args.shift || (out = readline('Enter gem name', force: true))
1248
+ list = []
1249
+ pwd_set do
1250
+ pat = /^#{name}\s+\((.+)\)$/
1251
+ IO.popen(gem_output("list -a #{shell_quote(name)}").to_s).each do |val|
1252
+ next unless val =~ pat
1253
+
1254
+ split_escape($1).each { |s| list << s unless s.start_with?('default:') }
1255
+ break
1256
+ end
1257
+ end
1258
+ ver = choice_index('Select version', list, force: out.nil?) unless list.empty?
1259
+ if ver
1260
+ op << '--force'
1261
+ op.unshift("#{name}@#{ver}")
1262
+ else
1263
+ op.unshift(name)
1264
+ end
1240
1265
  end
1241
1266
  raise_error ArgumentError, 'missing gem name', hint: flag if op.empty?
1242
1267
  if op.arg?('all')
@@ -1246,7 +1271,7 @@ module Squared
1246
1271
  else
1247
1272
  op.clear
1248
1273
  end
1249
- elsif (n = op.index { |val| val.match?(/(\A|[a-z])@\d/) })
1274
+ elsif (n = op.index { |val| val.match?(/(\A|[\w.-])@\d/) })
1250
1275
  name = op.remove_at(n)
1251
1276
  n = name.index('@')
1252
1277
  pre, ver = if n == 0
@@ -1254,13 +1279,13 @@ module Squared
1254
1279
  else
1255
1280
  [name[0, n], name[n.succ..-1]]
1256
1281
  end
1257
- op.adjoin(pre, basic_option('version', ver))
1282
+ op.adjoin(pre, quote_option('version', ver))
1258
1283
  .clear
1259
1284
  end
1260
1285
  if flag == :install
1261
- op.append_any
1286
+ op.append_any(escape: true)
1262
1287
  else
1263
- op.append
1288
+ op.append(escape: true)
1264
1289
  end
1265
1290
  op.delim << post if post
1266
1291
  when :check, :cleanup, :contents, :fetch, :list, :lock, :rdoc
@@ -1540,6 +1565,73 @@ module Squared
1540
1565
  run(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception?), from: :rubocop)
1541
1566
  end
1542
1567
 
1568
+ def serve(root, *, bind: nil, port: 3000, **kwargs)
1569
+ require 'webrick'
1570
+ config = kwargs.merge({ DocumentRoot: root })
1571
+ config[:BindAddress] = bind if bind
1572
+ config[:Port] = port if port
1573
+ server = WEBrick::HTTPServer.new(config)
1574
+ trap 'INT' do
1575
+ server.shutdown
1576
+ end
1577
+ server.start
1578
+ end
1579
+
1580
+ def vmname(bin: false)
1581
+ order = { 'rbenv' => -1, 'rvm' => -1, 'chruby' => -1, 'mise' => -1 }
1582
+ ENV.fetch('PATH', '').split(':').each_with_index do |val, index|
1583
+ order.each_key do |key|
1584
+ next unless val.match?(%r{[/.]#{key}/})
1585
+
1586
+ order[key] = index
1587
+ break
1588
+ end
1589
+ end
1590
+ if @asdf
1591
+ [File.join(ENV.fetch('ASDF_DATA_DIR', '$HOME/.asdf'), "installs/#{@asdf.first}")]
1592
+ else
1593
+ [
1594
+ "#{ENV.fetch('RBENV_ROOT', '$HOME/.rbenv')}/bin/rbenv",
1595
+ '$HOME/.rvm/bin/rvm',
1596
+ '$HOME/.local/bin/mise',
1597
+ '/usr/bin/rbenv',
1598
+ '/usr/bin/mise',
1599
+ '/usr/local/rvm/bin/rvm',
1600
+ '/usr/share/rvm/bin/rvm',
1601
+ '/usr/local/share/chruby/chruby.sh'
1602
+ ]
1603
+ .sort do |a, b|
1604
+ c = -1
1605
+ d = -1
1606
+ order.each do |key, val|
1607
+ pat = %r{/\.?#{key}}
1608
+ c = val if a.match?(pat)
1609
+ d = val if b.match?(pat)
1610
+ end
1611
+ if c == d
1612
+ 0
1613
+ elsif c == -1
1614
+ 1
1615
+ elsif d == -1
1616
+ -1
1617
+ else
1618
+ c < d ? -1 : 1
1619
+ end
1620
+ end
1621
+ end
1622
+ .each do |val|
1623
+ next unless File.exist?(val = val.sub('$HOME', Dir.home))
1624
+
1625
+ case (ret = File.basename(val, '.*'))
1626
+ when 'rvm', 'rbenv', 'mise', 'chruby'
1627
+ return bin ? [ret, val] : ret
1628
+ else
1629
+ return bin ? ['asdf', val] : 'asdf' if @asdf
1630
+ end
1631
+ end
1632
+ nil
1633
+ end
1634
+
1543
1635
  def gemspec
1544
1636
  @gemspec = !gemfile.nil? && Gem::Specification.load(gemfile.to_s) rescue false if @gemspec.nil?
1545
1637
  @gemspec || nil
@@ -1562,7 +1654,7 @@ module Squared
1562
1654
  def copy?
1563
1655
  return true if @copy.is_a?(Hash) ? copy[:into] : super
1564
1656
  return gemdir? if gemdir
1565
- return false unless @autodetect
1657
+ return false unless autodetect
1566
1658
 
1567
1659
  set = lambda do |val, path|
1568
1660
  base = Pathname.new(path.strip)
@@ -1575,7 +1667,7 @@ module Squared
1575
1667
  end
1576
1668
  if version
1577
1669
  begin
1578
- case @autodetect
1670
+ case autodetect
1579
1671
  when 'rvm'
1580
1672
  pwd_set { `rvm info homes` }[/^\s+gem:\s+"(.+)"$/, 1]
1581
1673
  when 'rbenv'
@@ -1583,8 +1675,10 @@ module Squared
1583
1675
  File.join($1, 'lib/ruby/gems', "#{$2}.0")
1584
1676
  end
1585
1677
  when 'asdf', 'mise'
1586
- val = pwd_set { `#{@autodetect} where ruby`.chomp }
1587
- File.join(val, 'lib/ruby/gems', "#{$1}.0") if val =~ /(\d\.\d)\.[^.]+$/
1678
+ pwd_set do
1679
+ val = `#{autodetect} where ruby`.chomp
1680
+ File.join(val, 'lib/ruby/gems', "#{$1}.0") if val =~ /(\d\.\d)\.[^.]+$/
1681
+ end
1588
1682
  when /bundler?/
1589
1683
  pwd_set { `bundle env` }[/^\s+Gem Path\s+(.+)$/, 1].split(File::PATH_SEPARATOR).find do |val|
1590
1684
  Dir.exist?(File.join(val, 'gems'))
@@ -1633,7 +1727,7 @@ module Squared
1633
1727
  log.error e
1634
1728
  self.version = nil
1635
1729
  @gemdir = nil
1636
- @autodetect = false
1730
+ self.autodetect = false
1637
1731
  else
1638
1732
  gemdir?
1639
1733
  end
@@ -1734,7 +1828,7 @@ module Squared
1734
1828
 
1735
1829
  def unpack_get(tag, ext)
1736
1830
  if ext == 'gem'
1737
- "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
1831
+ "https://rubygems.org/downloads/#{tag.sub_ext('.gem')}"
1738
1832
  else
1739
1833
  super
1740
1834
  end
@@ -1873,6 +1967,13 @@ module Squared
1873
1967
  semgte?(ver.to_s, min.to_s) && (max == Float::INFINITY || !semgte?(ver.to_s, max.to_s))
1874
1968
  end
1875
1969
  end
1970
+
1971
+ def serve?
1972
+ !Gem::Specification.find_by_name('webrick').nil?
1973
+ rescue Gem::MissingSpecError => e
1974
+ log.warn e if @serve
1975
+ false
1976
+ end
1876
1977
  end
1877
1978
 
1878
1979
  Application.implement Ruby
@@ -27,7 +27,7 @@ module Squared
27
27
  def multiple=(val)
28
28
  case val
29
29
  when Enumerable
30
- @multiple.concat(val.to_a.map { |val| val.is_a?(Regexp) ? val : val.to_s })
30
+ @multiple.concat(val.to_a.map { |pat| pat.is_a?(Regexp) ? pat : pat.to_s })
31
31
  when String, Symbol, Pathname
32
32
  @multiple << val.to_s
33
33
  when Regexp