squared 0.4.8 → 0.4.9

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.
@@ -213,7 +213,7 @@ module Squared
213
213
  file = val.is_a?(String) ? Time.now.strftime(val) : "#{@name}-#{Date.today}.log"
214
214
  end
215
215
  if file
216
- file = (val = env('LOG_DIR')) ? @workspace.home.join(val, file) : @workspace.home.join(file)
216
+ file = (val = env('LOG_DIR')) ? @workspace.home.join(val, file) : @workspace.home + file
217
217
  begin
218
218
  file = file.realdirpath
219
219
  rescue StandardError => e
@@ -225,7 +225,7 @@ module Squared
225
225
  end
226
226
  log[:progname] ||= @name
227
227
  if (val = env('LOG_LEVEL', ignore: false))
228
- log[:level] = val.match?(/^\d$/) ? log_sym(val.to_i) : val
228
+ log[:level] = val.match?(/\d/) ? log_sym(val.to_i) : val
229
229
  end
230
230
  log.delete(:file)
231
231
  @log = [file, log]
@@ -240,10 +240,10 @@ module Squared
240
240
  unless @output[0] == false || @output[0].is_a?(Array)
241
241
  if (val = env('BUILD', suffix: 'OPTS'))
242
242
  n = @output[0] ? 1 : 3
243
- @output[n] = merge_opts(@output[n], shell_split(val, escape: false))
243
+ @output[n] = merge_opts(@output[n], shell_split(val))
244
244
  end
245
245
  if (val = env(ref.to_s.upcase, suffix: 'OPTS'))
246
- @output[4] = merge_opts(@output[4], shell_split(val, escape: false))
246
+ @output[4] = merge_opts(@output[4], shell_split(val))
247
247
  end
248
248
  end
249
249
  @version = val if (val = env('BUILD', suffix: 'VERSION'))
@@ -324,7 +324,7 @@ module Squared
324
324
  else
325
325
  force = args.fetch(:force, false)
326
326
  end
327
- unpack(basepath(dir), uri: tag, digest: digest, ext: ext, force: force)
327
+ unpack(path + dir, uri: tag, digest: digest, ext: ext, force: force)
328
328
  end
329
329
  end
330
330
  end
@@ -401,10 +401,10 @@ module Squared
401
401
  self
402
402
  end
403
403
 
404
- def build(*args, sync: invoked_sync?('build'), from: @buildtype || :build, **)
404
+ def build(*args, sync: invoked_sync?('build'), from: :run, **)
405
405
  banner = verbose
406
406
  if args.empty?
407
- return unless from == (@buildtype || :build)
407
+ return unless from == :run
408
408
 
409
409
  run_b(@run, sync: sync, from: from) if series?(@run)
410
410
  args = @output
@@ -443,7 +443,7 @@ module Squared
443
443
  cmd, opts, var, flags, extra = args
444
444
  end
445
445
  if cmd
446
- cmd = as_get(cmd)
446
+ cmd = as_get cmd
447
447
  opts = compose(opts, script: false) if opts && respond_to?(:compose)
448
448
  flags = append_hash(flags).join(' ') if flags.is_a?(Hash)
449
449
  case opts
@@ -461,6 +461,7 @@ module Squared
461
461
  return unless (opts || extra) && respond_to?(:compose)
462
462
 
463
463
  cmd = compose(as_get(opts), flags, script: true, args: extra, from: from)
464
+ from = :script if from == :run && script?
464
465
  end
465
466
  run(cmd, var, from: from, banner: banner, sync: sync)
466
467
  end
@@ -516,13 +517,13 @@ module Squared
516
517
  else
517
518
  if @clean.is_a?(Enumerable) && !series?(@clean)
518
519
  @clean.each do |val|
519
- path = basepath(val = val.to_s)
520
- if path.directory? && val.match?(%r{[\\/]$})
521
- log&.warn "rm -rf #{path}"
522
- rm_rf(path, verbose: verbose)
520
+ entry = path + (val = val.to_s)
521
+ if entry.directory? && val.match?(%r{[\\/]$})
522
+ log&.warn "rm -rf #{entry}"
523
+ rm_rf(entry, verbose: verbose)
523
524
  else
524
- log&.warn "rm #{path}"
525
- (val.include?('*') ? Dir[path] : [path]).each do |file|
525
+ log&.warn "rm #{entry}"
526
+ (val.include?('*') ? Dir[entry] : [entry]).each do |file|
526
527
  next unless File.file?(file)
527
528
 
528
529
  begin
@@ -571,7 +572,7 @@ module Squared
571
572
  end
572
573
  end
573
574
 
574
- def unpack(target, sync: true, uri: nil, digest: nil, ext: nil, force: false, depth: 1, headers: {},
575
+ def unpack(target, uri:, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {},
575
576
  from: :unpack)
576
577
  if !target.exist?
577
578
  target.mkpath
@@ -685,7 +686,7 @@ module Squared
685
686
  break unless entry.directory?
686
687
 
687
688
  i = 0
688
- while (dest = target.join("#{File.basename(file.path)}-#{i}")).exist?
689
+ while (dest = target + "#{File.basename(file.path)}-#{i}").exist?
689
690
  i += 1
690
691
  end
691
692
  FileUtils.mv(entry, dest)
@@ -915,7 +916,7 @@ module Squared
915
916
  end
916
917
  return
917
918
  end
918
- cmd = session_done(cmd)
919
+ cmd = session_done cmd
919
920
  log&.info cmd
920
921
  on :first, from
921
922
  begin
@@ -1122,7 +1123,7 @@ module Squared
1122
1123
  end
1123
1124
  ret = JoinSet.new(cmd.flatten(1))
1124
1125
  if options && (val = env("#{prefix}_OPTIONS"))
1125
- split_escape(val).each { |opt| ret.last(fill_option(opt), /^(--?[^ =]+)[ =].+$/) }
1126
+ split_escape(val).each { |opt| ret.last(fill_option(opt), /\A(--?[^ =]+)[ =].+\z/m) }
1126
1127
  end
1127
1128
  main ? @session = ret : ret
1128
1129
  end
@@ -1130,7 +1131,7 @@ module Squared
1130
1131
  def session_delete(*args, target: @session)
1131
1132
  ret = []
1132
1133
  args.each do |val|
1133
- pat = /^#{Regexp.escape(shell_option(val))}(?: |=|$)/
1134
+ pat = /\A#{Regexp.escape(shell_option(val))}(?: |=|\z)/
1134
1135
  if (key = target.find { |opt| opt.match?(pat) })
1135
1136
  target.delete(key)
1136
1137
  ret << key
@@ -1172,6 +1173,10 @@ module Squared
1172
1173
  OptionPartition.clear(target, opts, styles: theme[:inline], **kwargs)
1173
1174
  end
1174
1175
 
1176
+ def print_success(*)
1177
+ puts 'Success'
1178
+ end
1179
+
1175
1180
  def print_item(*val)
1176
1181
  puts if @@print_order > 0 && stdout?
1177
1182
  @@print_order += 1
@@ -1204,7 +1209,7 @@ module Squared
1204
1209
 
1205
1210
  def print_footer(*lines, sub: nil, reverse: false, right: false, **kwargs)
1206
1211
  n = Project.max_width(lines)
1207
- sub = as_a(sub)
1212
+ sub = as_a sub
1208
1213
  lines.map! do |val|
1209
1214
  s = right ? val.rjust(n) : val.ljust(n)
1210
1215
  sub.each { |h| s = sub_style(s, **h) }
@@ -1471,7 +1476,7 @@ module Squared
1471
1476
  end
1472
1477
  end
1473
1478
 
1474
- def param_guard(action, flag, args: nil, key: nil, pat: nil, values: nil)
1479
+ def param_guard(action, flag, args:, key: nil, pat: nil, values: nil)
1475
1480
  if args && key
1476
1481
  val = args.fetch(key, nil)
1477
1482
  return val unless val.nil? || (pat && !val.match?(pat)) || (values && !values.include?(val))
@@ -1497,24 +1502,59 @@ module Squared
1497
1502
  b = sub_style("#{pkg} #{ver}", styles: theme[:inline])
1498
1503
  c, d = rev == 1 || lock ? ['y/N', 'N'] : ['Y/n', 'Y']
1499
1504
  e = lock ? " #{sub_style('(locked)', styles: color(:red))}" : ''
1500
- confirm("Upgrade to #{a}? #{b + e} [#{c}] ", d, timeout: 60)
1505
+ confirm("Upgrade to #{a}? #{b + e} [#{c}] ", d)
1501
1506
  end
1502
1507
 
1503
- def choice_index(msg, list, values: nil, multiple: false, accept: nil, trim: nil)
1504
- puts if @@print_order > 0
1505
- raise_error 'user cancelled' unless (ret = choice(msg, list, multiple: multiple))
1508
+ def choice_index(msg, list, values: nil, multiple: false, accept: nil, series: false, trim: nil, column: nil,
1509
+ attempts: 5, force: true)
1510
+ puts if !series && @@print_order > 0
1511
+ msg = "#{msg} (optional)" unless force
1512
+ unless (ret = choice(msg, list, multiple: multiple, force: force, attempts: attempts)) || !force
1513
+ raise_error 'user cancelled'
1514
+ end
1515
+ if ret.nil? || ret.empty?
1516
+ return unless force
1517
+
1518
+ exit 1
1519
+ end
1506
1520
  ret = multiple ? ret.map! { |val| val.sub(trim, '') } : ret.sub(trim, '') if trim
1507
- exit 1 if accept && !confirm("#{accept} [#{ret.join(', ')}] [y/N] ", 'N', timeout: 60)
1521
+ if column
1522
+ a, b = as_a(column)
1523
+ ret = as_a(ret).map! { |val| val[a, b || 1] }
1524
+ ret = ret.first unless multiple
1525
+ end
1526
+ if accept
1527
+ a = as_a(ret).map { |val| sub_style(val, styles: theme[:inline]) }.join(', ')
1528
+ accept = as_a(accept).map { |val| as_a(val) }
1529
+ if accept.any? { |val| val[1] == true }
1530
+ ret = [ret]
1531
+ multiple = -1
1532
+ end
1533
+ loop do
1534
+ c = confirm("#{accept.first[0]}#{a ? " [#{a}]" : ''} [y/N] ", 'N', timeout: 60)
1535
+ if accept.shift[1] == true
1536
+ ret << c
1537
+ elsif !c
1538
+ break
1539
+ end
1540
+ a = nil
1541
+ break if accept.empty?
1542
+ end
1543
+ exit 1 unless accept.empty?
1544
+ end
1508
1545
  if values
1509
- ret = [ret]
1546
+ ret = [ret] unless accept && multiple == -1
1510
1547
  values.each do |val|
1511
- val, req = val if val.is_a?(Array)
1512
- val = Readline.readline("#{val} (#{req ? 'required' : 'optional'}): ", true).strip
1513
- raise_error 'user cancelled' if req && val.empty?
1548
+ if val.is_a?(Array)
1549
+ val, force = val
1550
+ else
1551
+ force = false
1552
+ end
1553
+ val = readline(val, force: force)
1514
1554
  ret << (val.empty? ? nil : val)
1515
1555
  end
1516
1556
  end
1517
- @@print_order += 1
1557
+ @@print_order += 1 unless series
1518
1558
  ret
1519
1559
  end
1520
1560
 
@@ -1547,7 +1587,7 @@ module Squared
1547
1587
  raise_error 'pathspec not within worktree' unless pass || files.size == proj.size
1548
1588
  files = proj
1549
1589
  end
1550
- files.map { |val| val == '.' ? '.' : shell_quote(basepath(val)) }
1590
+ files.map { |val| val == '.' ? '.' : shell_quote(path + val) }
1551
1591
  end
1552
1592
 
1553
1593
  def semver(val)
@@ -1583,7 +1623,7 @@ module Squared
1583
1623
  end
1584
1624
 
1585
1625
  def colormap(val)
1586
- val.compact.map! { |s| color(s) }.flatten
1626
+ val.compact.flat_map { |s| color(s) }
1587
1627
  end
1588
1628
 
1589
1629
  def epochtime
@@ -1592,7 +1632,7 @@ module Squared
1592
1632
 
1593
1633
  def verbosetype
1594
1634
  case verbose
1595
- when TrueClasss
1635
+ when TrueClass
1596
1636
  1
1597
1637
  when Numeric
1598
1638
  verbose.succ
@@ -1627,7 +1667,7 @@ module Squared
1627
1667
  pwd = Pathname.pwd
1628
1668
  if block_given?
1629
1669
  begin
1630
- if path == pwd || pass == true || (pass.is_a?(String) && semscan(pass).join >= RUBY_VERSION)
1670
+ if path == pwd || pass == true || (pass.is_a?(String) && semscan(pass).join <= RUBY_VERSION)
1631
1671
  ret = yield
1632
1672
  else
1633
1673
  Dir.chdir(path)
@@ -1794,6 +1834,10 @@ module Squared
1794
1834
  end
1795
1835
  end
1796
1836
 
1837
+ def success?(ret)
1838
+ ret == true && stdout? && banner?
1839
+ end
1840
+
1797
1841
  def banner?
1798
1842
  ARG[:BANNER] && !env('BANNER', equals: '0')
1799
1843
  end
@@ -4,8 +4,6 @@ module Squared
4
4
  module Workspace
5
5
  module Project
6
6
  class Docker < Base
7
- include Prompt
8
-
9
7
  COMPOSEFILE = %w[compose.yaml compose.yml docker-compose.yaml compose.yml docker-compose.yml].freeze
10
8
  BAKEFILE = %w[docker-bake.json docker-bake.hcl docker-bake.override.json docker-bake.override.hcl].freeze
11
9
  DIR_DOCKER = (COMPOSEFILE + BAKEFILE).freeze
@@ -37,15 +35,15 @@ module Squared
37
35
  run: %w[d|detach init i|interactive no-healthcheck oom-kill-disable privileged P|publish-all q|quiet
38
36
  read-only rm runtime t|tty add-host=q annotation=q a|attach=b blkio-weight-device=i cap-add=b
39
37
  cap-drop=b cgroup-parent=b cgroupns=b cidfile=p detach-keys=q device=q device-cgroup-rule=q
40
- device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q
41
- disable-content-trust=b? dns=e dns-option=e dns-search=e domainname=b entrypoint=q e|env=qq
42
- env-file=p expose=e gpus=q group-add=b health-cmd=q health-interval=b health-retries=i
43
- health-start-interval=b health-start-period=b health-timeout=b h|hostname=e io-maxbandwidth=b
44
- io-maxiops=b ip=b ip6=e ipc=b isolation=b kernel-memory=b l|label=q label-file=p link=b
45
- link-local-ip=b log-driver=b log-opt=q mac-address=e memory-swappiness=b mount=qq name=b network=b
46
- network-alias=b oom-score-adj=b pid=b platform=b p|publish=e pull=b restart=b runtime=b
47
- security-opt=q shm-size=b sig-proxy=b? stop-signal=b stop-timeout=i storage-opt=q sysctl=q tmpfs=q
48
- ulimit=q user=e userns=b uts=b v|volume=q volume-driver=b volumes-from=b w|workdir=q].freeze,
38
+ device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q disable-content-trust=b?
39
+ dns=e dns-option=e dns-search=e domainname=b entrypoint=q e|env=qq env-file=p expose=e gpus=q
40
+ group-add=b health-cmd=q health-interval=b health-retries=i health-start-interval=b
41
+ health-start-period=b health-timeout=b h|hostname=e io-maxbandwidth=b io-maxiops=b ip=b ip6=e ipc=b
42
+ isolation=b kernel-memory=b l|label=q label-file=p link=b link-local-ip=b log-driver=b log-opt=q
43
+ mac-address=e memory-swappiness=b mount=qq name=b network=b network-alias=b oom-score-adj=b pid=b
44
+ platform=b p|publish=e pull=b restart=b runtime=b security-opt=q shm-size=b sig-proxy=b?
45
+ stop-signal=b stop-timeout=i storage-opt=q sysctl=q tmpfs=q ulimit=q user=e userns=b uts=b
46
+ v|volume=q volume-driver=b volumes-from=b w|workdir=q].freeze,
49
47
  exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p user=e
50
48
  w|workdir=q].freeze,
51
49
  update: %w[blkio-weight=i cpu-period=i cpu-quota=i cpu-rt-period=i cpu-rt-runtime=i c|cpu-shares=i cpus=f
@@ -163,7 +161,7 @@ module Squared
163
161
  when 'container'
164
162
  case flag
165
163
  when :exec, :commit
166
- format_desc(action, flag, flag == :exec ? 'id/name?,opts*,args+' : 'id/name,tag?,opts*')
164
+ format_desc(action, flag, flag == :exec ? 'id/name,opts*,args+' : 'id/name,tag?,opts*')
167
165
  task flag, [:id] do |_, args|
168
166
  if flag == :exec && !args.id
169
167
  choice_command flag
@@ -173,7 +171,7 @@ module Squared
173
171
  end
174
172
  end
175
173
  when :run
176
- format_desc action, flag, 'image?,opts*,args*'
174
+ format_desc action, flag, 'image,opts*,args*'
177
175
  task flag, [:image] do |_, args|
178
176
  if args.image
179
177
  container(flag, args.extras, id: args.image)
@@ -204,8 +202,8 @@ module Squared
204
202
  when 'network'
205
203
  format_desc action, flag, 'target,opts*'
206
204
  task flag, [:target] do |_, args|
207
- if (target = args.target)
208
- network(flag, args.extras, target: target)
205
+ if args.target
206
+ network(flag, args.extras, target: args.target)
209
207
  else
210
208
  choice_command flag
211
209
  end
@@ -307,7 +305,7 @@ module Squared
307
305
  end
308
306
  end
309
307
  op.append(args, escape: true)
310
- contextdir(context) if context
308
+ contextdir context if context
311
309
  end
312
310
  end
313
311
  op.clear(pass: false)
@@ -361,7 +359,7 @@ module Squared
361
359
  args << k
362
360
  next
363
361
  when 'source', 'src', 'destination', 'dst', 'target'
364
- v = basepath(v)
362
+ v = path + v
365
363
  v = shell_quote(v, option: false, force: false) if q == ''
366
364
  tmpfs = false if k[0] == 's'
367
365
  end
@@ -420,7 +418,7 @@ module Squared
420
418
  when :rm
421
419
  status = %w[created exited dead]
422
420
  end
423
- ps = docker_output('ps -a', *status.map { |s| "--filter='status=#{s}'" })
421
+ ps = docker_output('ps -a', *status.map { |s| "--filter=\"status=#{s}\"" })
424
422
  list_image(flag, ps, no: no, hint: "status: #{status.join(', ')}", from: from) do |img|
425
423
  run(cmd.temp(img), from: from)
426
424
  end
@@ -489,7 +487,7 @@ module Squared
489
487
  op.clear
490
488
  from = :"network:#{flag}"
491
489
  list_image(flag, docker_output('ps -a'), from: from) do |img|
492
- puts 'Success' if run(cmd.temp(target, img), from: from) == true && stdout? && banner?
490
+ print_success if success?(run(cmd.temp(target, img), from: from))
493
491
  end
494
492
  end
495
493
 
@@ -550,7 +548,7 @@ module Squared
550
548
  def append_file(type, target: @session)
551
549
  return unless type == 2 || type == 4 || @file.is_a?(Array)
552
550
 
553
- files = as_a(@file).map { |val| quote_option('file', basepath(val)) }
551
+ files = as_a(@file).map { |val| quote_option('file', path + val) }
554
552
  if target.is_a?(Set)
555
553
  target.merge(files)
556
554
  else
@@ -585,7 +583,7 @@ module Squared
585
583
  pwd_set do
586
584
  found = false
587
585
  index = 0
588
- pat = /^(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':').first})(?:[_.,:-]|$)/
586
+ pat = /^(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':', 2).first})(?:[_.,:-]|$)/
589
587
  IO.popen(session_done(cmd << '--format=json')).each do |line|
590
588
  data = JSON.parse(line)
591
589
  id = data['ID']
@@ -675,7 +673,7 @@ module Squared
675
673
  puts " # #{header}"
676
674
  case flag
677
675
  when :run, :exec
678
- values = [['Options', flag == :run], ['Command arguments', flag == :exec]]
676
+ values = [['Options', flag == :run], ['Arguments', flag == :exec]]
679
677
  cmd = flag.to_s
680
678
  else
681
679
  values = [['Options', false], ['Container', true]]
@@ -683,7 +681,7 @@ module Squared
683
681
  end
684
682
  out, opts, args = choice_index(msg, lines, values: values)
685
683
  ret = run docker_output(cmd, opts, '--', out.split(/\s+/)[index], args)
686
- puts 'Success' if ret && cmd.start_with?('network')
684
+ print_success if success?(ret && cmd.start_with?('network'))
687
685
  end
688
686
  end
689
687
 
@@ -703,7 +701,7 @@ module Squared
703
701
  end
704
702
 
705
703
  def contextdir(val = nil)
706
- val && projectpath?(val) ? shell_quote(basepath(val)) : '.'
704
+ val && projectpath?(val) ? shell_quote(path + val) : '.'
707
705
  end
708
706
 
709
707
  def tagname(val)