squared 0.8.3 → 0.8.4

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.
@@ -21,14 +21,14 @@ module Squared
21
21
  }.freeze,
22
22
  compose: {
23
23
  common: %w[all-resources ansi=b compatibility dry-run env-file=p f|file=p parallel=n profile=b progress=b
24
- project-directory=p p|project-name=e].freeze,
24
+ project-directory=p p|project-name=b].freeze,
25
25
  build: %w[check no-cache print pull push with-dependencies q|quiet build-arg=qq builder=b m|memory=b
26
26
  provenance=q sbom=q ssh=qq].freeze,
27
27
  create: %w[build force-recreate no-build no-recreate quiet-pull remove-orphans y|yes pull=b scale=i].freeze,
28
- exec: %w[d|detach privileged e|env=qq index=i T|no-TTY=b? user=e w|workdir=q].freeze,
28
+ exec: %w[d|detach privileged e|env=qq index=i T|no-tty user=b w|workdir=q].freeze,
29
29
  run: %w[build d|detach no-deps q|quiet quiet-build quiet-pull remove-orphans rm P|service-ports use-aliases
30
30
  cap-add=b cap-drop=b entrypoint=q e|env=qq env-from-file=p i|interactive=b? l|label=q name=b
31
- T|no-TTY=b? p|publish=q pull=b u|user=e v|volume=q w|workdir=q].freeze,
31
+ T|no-tty p|publish=q pull=b u|user=b v|volume=qq w|workdir=q].freeze,
32
32
  up: %w[abort-on-container-exit abort-on-container-failure always-recreate-deps attach-dependencies build
33
33
  d|detach force-recreate menu no-build no-color no-deps no-log-prefix no-recreate no-start quiet-build
34
34
  quiet-pull remove-orphans V|renew-anon-volumes timestamps wait w|watch y|yes attach=b
@@ -39,9 +39,9 @@ module Squared
39
39
  }.freeze,
40
40
  container: {
41
41
  create: %w[init i|interactive no-healthcheck oom-kill-disable privileged P|publish-all q|quiet read-only
42
- rm t|tty use-api-socket add-host=q annotation=q a|attach=b blkio-weight=i blkio-weight-device=i
43
- cap-add=b cap-drop=b cgroup-parent=b cgroupns=b cidfile=p device=q device-cgroup-rule=q
44
- device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q
42
+ rm t|tty use-api-socket add-host=q annotation=q a|attach=b blkio-weight=i
43
+ blkio-weight-device=i cap-add=b cap-drop=b cgroup-parent=b cgroupns=b cidfile=p device=q
44
+ device-cgroup-rule=q device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q
45
45
  dns=q dns-option=q dns-search=q domainname=b entrypoint=q e|env=qq env-file=p expose=q gpus=q
46
46
  group-add=b health-cmd=q health-interval=b health-retries=i health-start-interval=q
47
47
  health-start-period=q health-timeout=q hostname=q io-maxbandwidth=b io-maxiops=b ip=b ip6=q ipc=b
@@ -49,13 +49,14 @@ module Squared
49
49
  m|memory=b memory-reservation=b memory-swap=n memory-swappiness=n mount=qq name=b network=b
50
50
  network-alias=b oom-score-adj=b pid=b pids-limit=n platform=q p|publish=q pull=b restart=b
51
51
  runtime=b security-opt=q shm-size=b stop-signal=b stop-timeout=i storage-opt=q sysctl=q tmpfs=q
52
- ulimit=q u|user=b userns=b uts=b v|volume=q volume-driver=b volumes-from=b w|workdir=q].freeze,
52
+ ulimit=q u|user=b userns=b uts=b v|volume=qq volume-driver=b volumes-from=b w|workdir=q].freeze,
53
53
  run: %w[d|detach detach-keys=q sig-proxy=b?].freeze,
54
54
  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
55
55
  cpuset-cpus=b cpuset-mems=b m|memory=b memory-reservation=b memory-swap=n pids-limit=n
56
56
  restart=q].freeze,
57
- exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p u|user=e
57
+ exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p u|user=b
58
58
  w|workdir=q].freeze,
59
+ rm: %w[f|force l|link v|volumes].freeze,
59
60
  commit: %w[no-pause a|author=q c|change=q m|message=q].freeze,
60
61
  logs: %w[details f|follow t|timestamps since=q n|tail=b until=q].freeze,
61
62
  inspect: %w[s|size f|format=q].freeze,
@@ -64,12 +65,12 @@ module Squared
64
65
  restart: %w[s|signal=b t|timeout=i].freeze,
65
66
  kill: %w[s|signal=b].freeze,
66
67
  stats: %w[a|all no-stream no-trunc format|q].freeze,
67
- attach: %w[no-stdin detach-keys=q sig-proxy=!?].freeze
68
+ attach: %w[no-stdin detach-keys=q sig-proxy].freeze
68
69
  }.freeze,
69
70
  image: {
70
71
  common: %w[platform=q].freeze,
71
72
  inspect: %w[f|format].freeze,
72
- history: %w[f|format no-trunc q|quiet H|human=!?].freeze,
73
+ history: %w[f|format no-trunc q|quiet H|human].freeze,
73
74
  ls: %w[a|all digests no-trunc q|quiet tree f|filter=q format=q].freeze,
74
75
  pull: %w[a|all-tags q|quiet].freeze,
75
76
  push: %w[a|all-tags q|quiet].freeze,
@@ -108,6 +109,10 @@ module Squared
108
109
  [].freeze
109
110
  end
110
111
 
112
+ def bannerargs
113
+ %i[context registry tag].freeze
114
+ end
115
+
111
116
  def config?(val)
112
117
  return false unless (val = as_path(val))
113
118
 
@@ -120,43 +125,40 @@ module Squared
120
125
  'compose' => %i[build create publish run exec up down logs service].freeze,
121
126
  'bake' => %i[build compose check].freeze,
122
127
  'image' => %i[ls rm pull push tag save inspect history].freeze,
123
- 'container' => %i[attach commit create diff exec logs top inspect kill pause restart rm run start stats stop
128
+ 'container' => %i[attach commit create diff exec inspect kill logs pause restart rm run start stats stop top
124
129
  unpause update].freeze,
125
130
  'network' => %i[connect disconnect create].freeze,
126
131
  'ls' => nil
127
132
  })
128
133
 
129
134
  attr_reader :context
130
- attr_accessor :tag
135
+ attr_accessor :registry, :tag
131
136
 
132
- def initialize(*, client: nil, mounts: [], **kwargs)
137
+ def initialize(*, **kwargs)
133
138
  super
134
139
  self.global = nil
135
140
  return unless dockerfile(kwargs[:file]).exist?
136
141
 
137
- @tag = kwargs[:tag] || tagname("#{@project}:#{@version || 'latest'}")
142
+ @tag = env('TAG', strict: true,
143
+ ignore: false) || kwargs[:tag] || tagname(@project, @version || 'latest')
138
144
  @context = kwargs[:context]
139
- @client = if client
140
- opts = []
141
- client.each do |key, val|
142
- val = case (key = key.to_s)
143
- when 'config'
144
- basepath!(val, type: 'd')
145
- when 'tlscacert', 'tlscert', 'tlskey'
146
- basepath!(val, type: 'f')
147
- when 'context', 'host', 'log-level'
148
- quote_option(key, val)
149
- when 'debug', 'tls', 'tlsverify'
150
- opts << key
151
- next
152
- end
153
- opts << quote_option(key, val) if val
154
- end
155
- opts unless opts.empty?
156
- end
157
- @mounts = mounts
145
+ @client = kwargs[:client]&.each_with_object([]) do |(key, val), out|
146
+ val = case (key = key.to_s)
147
+ when 'config'
148
+ basepath!(val, type: 'd')
149
+ when 'tlscacert', 'tlscert', 'tlskey'
150
+ basepath!(val, type: 'f')
151
+ when 'context', 'host', 'log-level'
152
+ quote_option(key, val)
153
+ when 'debug', 'tls', 'tlsverify'
154
+ out << key
155
+ next
156
+ end
157
+ out << quote_option(key, val) if val
158
+ end
159
+ @mounts = Array(kwargs[:mounts])
158
160
  @secrets = kwargs[:secrets]
159
- @registry = tagjoin kwargs[:registry], kwargs[:username]
161
+ self.registry = tagjoin kwargs[:registry], kwargs[:username]
160
162
  @oci = tagjoin kwargs[:oci], kwargs[:username]
161
163
  initialize_ref Docker.ref
162
164
  initialize_logger kwargs[:log]
@@ -229,7 +231,7 @@ module Squared
229
231
  format_desc action, flag, 'opts*,target*,context?|:'
230
232
  task flag do |_, args|
231
233
  args = args.to_a
232
- if args.first == ':'
234
+ if choice!(args)
233
235
  choice_command :bake
234
236
  else
235
237
  buildx(:bake, args, from: (:'buildx:bake' if flag == :compose))
@@ -253,14 +255,14 @@ module Squared
253
255
  compose_(flag, args.extras, service: service)
254
256
  end
255
257
  when :service
256
- cmds = %w[down kill pause restart rm start stop top unpause watch].freeze
258
+ cmds = %w[down kill logs pause restart rm start stop top unpause watch].freeze
257
259
  format_desc(action, flag, cmds, arg: nil, after: 'name+|:')
258
260
  task flag, [:command] do |_, args|
259
261
  cmd = param_guard(action, flag, args: args, key: :command)
260
262
  raise ArgumentError, message('unrecognized command', hint: cmd) unless cmds.include?(cmd)
261
263
 
262
264
  service = args.extras
263
- if service.first == ':'
265
+ if choice!(service)
264
266
  choice_command flag, cmd
265
267
  else
266
268
  compose_(flag, [cmd], service: service.empty? || service)
@@ -313,11 +315,13 @@ module Squared
313
315
  when 'image'
314
316
  case flag
315
317
  when :push
316
- next unless @registry
317
-
318
- format_desc action, flag, 'tag?,registry/username?,opts*'
318
+ format_desc action, flag, 'tag?,registry/username?|:,opts*'
319
319
  task flag do |_, args|
320
- image flag, args.to_a
320
+ args = args.to_a
321
+ if choice!(args, first: false) || !self.registry
322
+ registry = readline('Enter registry/username', force: true)
323
+ end
324
+ image(flag, args, id: id, registry: registry)
321
325
  end
322
326
  when :pull
323
327
  format_desc action, flag, 'tag,registry/username?,opts*'
@@ -423,11 +427,7 @@ module Squared
423
427
  else
424
428
  ret.merge(Array(@secrets).map { |arg| quote_option('secret', arg) })
425
429
  end
426
- if (val = option('tag', ignore: false))
427
- append_tag val
428
- elsif !session_arg?('t', 'tag')
429
- append_tag tag
430
- end
430
+ append_tag option('tag', ignore: false) or session_arg?('t', 'tag') ? nil : tag
431
431
  append_context
432
432
  when :bake, :compose
433
433
  option(from == :bake ? 'target' : 'service', ignore: false) { |val| ret.merge(split_escape(val).quote!) }
@@ -436,15 +436,15 @@ module Squared
436
436
  end
437
437
 
438
438
  def buildx(flag, opts = [], tag: nil, context: nil, from: nil)
439
+ bx = OPT_DOCKER[:buildx]
439
440
  if flag == :bake && context&.match?(%r{^["']?(https?|git)://}i)
440
- shared = data[:shared].dup.push('f|file=q')
441
+ shared = bx[:shared].dup.push('f|file=q')
441
442
  shared.delete('f|file=p')
442
443
  end
443
444
  cmd, opts = docker_session('buildx', opts: opts)
444
- data = OPT_DOCKER[:buildx]
445
- op = OptionPartition.new(opts, data[:common], cmd, project: self, strict: strict?)
445
+ op = OptionPartition.new(opts, bx[:common], cmd, **dockerinit)
446
446
  op.append(flag, quote: false)
447
- .parse(data[flag == :bake ? :bake : :build] + (shared || data[:shared]))
447
+ .parse(bx[flag == :bake ? :bake : :build] + (shared || bx[:shared]))
448
448
  case flag
449
449
  when :build, :context
450
450
  append_tag tag || option('tag', ignore: false) || self.tag
@@ -455,6 +455,10 @@ module Squared
455
455
  end
456
456
  when :bake
457
457
  append_file(0, index: 3) unless from || op.arg?('f', 'file') || !anypath?(*COMPOSEFILE)
458
+ if op.first == '-'
459
+ op.shift
460
+ op << @output[4] if @output[4]
461
+ end
458
462
  unless op.empty?
459
463
  if !context && op.size > 1 && exist?(op.last, type: 'd')
460
464
  pat = /\btarget\s+"#{Regexp.escape(op.last)}"/
@@ -476,7 +480,7 @@ module Squared
476
480
  if flag == :service
477
481
  command = opts.first
478
482
  if service == true
479
- cmd, status = filter_ps command, from
483
+ cmd, status = filter_ps(command, from: from)
480
484
  lines = IO.popen(cmd.temp('--services')).map(&:strip).reject(&:empty?)
481
485
  return list_empty(hint: status) if lines.empty?
482
486
 
@@ -485,10 +489,11 @@ module Squared
485
489
  docker_session('compose', command, '--', *service)
486
490
  else
487
491
  cmd, opts = docker_session('compose', opts: opts)
488
- op = OptionPartition.new(opts, OPT_DOCKER[:compose][:common], cmd, project: self, strict: strict?)
492
+ cp = OPT_DOCKER[:compose]
493
+ op = OptionPartition.new(opts, cp[:common], cmd, **dockerinit)
489
494
  append_file(filetype, force: flag == :publish) unless op.arg?('f', 'file')
490
495
  op << flag
491
- op.parse(OPT_DOCKER[:compose].fetch(flag, []))
496
+ op.parse(cp.fetch(flag, []))
492
497
  if flag == :publish
493
498
  id ||= option('tag', ignore: false) || op.shift || tagmain
494
499
  registry ||= option('registry') || op.shift || @oci
@@ -519,18 +524,19 @@ module Squared
519
524
 
520
525
  def container(flag, opts = [], id: nil)
521
526
  cmd, opts = docker_session('container', flag, opts: opts)
522
- data = OPT_DOCKER[:container]
523
- list = data.fetch(flag, [])
524
- list += data[:create] if (rc = flag == :run)
525
- list += data[:update] if rc ||= flag == :create
526
- op = OptionPartition.new(opts, list, cmd, project: self, strict: strict?, args: rc || flag == :exec)
527
+ rc = flag == :run
528
+ ct = OPT_DOCKER[:container]
529
+ list = ct.fetch(flag, [])
530
+ list += ct[:create] if rc
531
+ list += ct[:update] if rc ||= flag == :create
532
+ op = OptionPartition.new(opts, list, cmd, args: rc || flag == :exec, **dockerinit)
527
533
  from = symjoin 'container', flag
528
534
  case flag
529
535
  when :run, :create, :exec
530
536
  if rc && !op.arg?('mount')
531
537
  all = collect_hash VAL_DOCKER[:run]
532
538
  delim = Regexp.new(",\\s*(?=#{all.join('|')})")
533
- Array(@mounts).each do |val|
539
+ @mounts.each do |val|
534
540
  type = nil
535
541
  args = val.split(delim).each_with_object([]) do |opt, out|
536
542
  k, v, q = OptionPartition.parse_option(opt)
@@ -581,7 +587,7 @@ module Squared
581
587
  raise ArgumentError, message('unrecognized args', op.join(', '), hint: flag) unless op.empty?
582
588
  return unless confirm_command(cmd.to_s, title: from, target: id, as: latest)
583
589
 
584
- registry = option('registry') || @registry
590
+ registry = option('registry') || self.registry
585
591
  run(from: from, exception: registry.nil? ? exception? : true)
586
592
  return unless registry
587
593
 
@@ -597,7 +603,7 @@ module Squared
597
603
  return image(:push, opts, id: latest, registry: registry)
598
604
  else
599
605
  if op.empty?
600
- ps, status, no = filter_ps flag, from
606
+ ps, status, no = filter_ps(flag, from: from)
601
607
  cmd << '--no-stream' if flag == :stats
602
608
  list_image(flag, ps, no: no, hint: status, multiple: flag != :attach, from: from) do |img|
603
609
  run(cmd.temp(img), from: from)
@@ -621,9 +627,10 @@ module Squared
621
627
 
622
628
  def image(flag, opts = [], sync: true, id: nil, registry: nil, filter: nil)
623
629
  cmd, opts = docker_session('image', flag, opts: opts)
624
- list = OPT_DOCKER[:image].fetch(flag, [])
625
- list += OPT_DOCKER[:image][:common] unless flag == :ls || flag == :tag
626
- op = OptionPartition.new(opts, list, cmd, project: self, strict: strict?)
630
+ im = OPT_DOCKER[:image]
631
+ list = im.fetch(flag, [])
632
+ list += im[:common] unless flag == :ls || flag == :tag
633
+ op = OptionPartition.new(opts, list, cmd, **dockerinit)
627
634
  exception = exception?
628
635
  banner = true
629
636
  from = symjoin 'image', flag
@@ -640,11 +647,18 @@ module Squared
640
647
  break
641
648
  end
642
649
  list_image(:run, filter: filter, from: from) do |val|
643
- container(:run, if name
644
- opts.dup << "name=#{index == 0 ? name : "#{name}-#{index}"}"
645
- else
646
- opts
647
- end, id: val)
650
+ args = if name
651
+ opts.dup << "name=#{index == 0 ? name : "#{name}-#{index}"}"
652
+ elsif choice!(opts, only: true)
653
+ OptionPartition.strip(readline('Enter arguments', force: false))
654
+ else
655
+ opts
656
+ end
657
+ if args.none?(/^d(etach)?$/)
658
+ Thread.new(args.dup, val) { |a, id| container(:run, a, id: id) }.join
659
+ break
660
+ end
661
+ container(:run, args, id: val)
648
662
  index += 1
649
663
  end
650
664
  return
@@ -670,7 +684,7 @@ module Squared
670
684
  op << val
671
685
  found = true
672
686
  if flag == :tag
673
- op << tagname("#{project}:#{op.first}")
687
+ op << tagname(project, op.first)
674
688
  break
675
689
  end
676
690
  end
@@ -679,27 +693,27 @@ module Squared
679
693
  if !id
680
694
  id = tagmain
681
695
  elsif !op.arg?('a', 'all-tags') && !id.include?(':')
682
- id = "#{project}:#{id}"
696
+ id = tagname project, id
683
697
  end
684
698
  unless registry
685
699
  registry = op.shift
686
- registry ||= option('registry') || @registry unless id.include?('/')
700
+ registry ||= option('registry') || self.registry unless id.include?('/')
687
701
  end
688
702
  cmd << shell_quote(tagjoin(registry, id))
689
703
  when :push
690
704
  id ||= option('tag', ignore: false) || op.shift || tagmain
691
- registry ||= option('registry') || op.shift || @registry
705
+ registry ||= option('registry') || op.shift || self.registry
692
706
  emptyargs op, flag
693
707
  raise ArgumentError, message('username/registry not specified', hint: flag) unless registry
694
708
 
695
709
  uri = shell_quote tagjoin(registry, id)
696
710
  op << uri
697
- img = docker_output 'image', 'tag', id, uri
711
+ img = docker_output 'image tag', id, uri
698
712
  return unless confirm_command(img.to_s, cmd.to_s, target: id, as: registry, title: from)
699
713
 
700
714
  @session = img
701
715
  sync = false
702
- exception ||= true
716
+ exception = true
703
717
  banner = false
704
718
  when :inspect, :history
705
719
  raise ArgumentError, message('missing image', hint: flag) if op.empty?
@@ -716,7 +730,7 @@ module Squared
716
730
 
717
731
  def network(flag, opts = [], target: nil)
718
732
  cmd, opts = docker_session('network', flag, opts: opts)
719
- op = OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, project: self, strict: strict?)
733
+ op = OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, **dockerinit)
720
734
  .clear
721
735
  from = symjoin 'network', flag
722
736
  if flag == :create
@@ -767,7 +781,7 @@ module Squared
767
781
 
768
782
  def read_composefile(*keys, target: nil)
769
783
  require 'yaml'
770
- target = ENV['COMPOSE_FILE']&.split(workspace.windows? ? ';' : ':') unless target && !target.empty?
784
+ target = ENV['COMPOSE_FILE']&.split(windows? ? ';' : ':') unless target && !target.empty?
771
785
  Array(target || dockerfile).each do |val|
772
786
  doc = YAML.load_file(basepath(val))
773
787
  if keys.empty?
@@ -784,7 +798,7 @@ module Squared
784
798
  opts = OptionPartition.union(Array(opts), @client) if @client
785
799
  return session('docker', *cmd) unless opts
786
800
 
787
- op = OptionPartition.new(opts, OPT_DOCKER[:common], project: self, strict: strict?)
801
+ op = OptionPartition.new(opts, OPT_DOCKER[:common], **dockerinit)
788
802
  [session('docker', *op.to_a, *cmd), op.extras]
789
803
  end
790
804
 
@@ -792,12 +806,12 @@ module Squared
792
806
  session('docker', *cmd, main: false, options: false, **kwargs)
793
807
  end
794
808
 
795
- def append_command(flag, val, list, target: @session, prompt: ':')
796
- list << if list.delete(prompt)
797
- readline('Enter command [args]', force: flag == :exec)
798
- else
799
- env('DOCKER_ARGS')
800
- end
809
+ def append_command(flag, id, list, target: @session, prompt: ':')
810
+ if list.delete(prompt)
811
+ list << readline('Enter command [args]', force: flag == :exec)
812
+ elsif (val = env('DOCKER_ARGS'))
813
+ list << val
814
+ end
801
815
  case flag
802
816
  when :run
803
817
  unless session_arg?('name', target: target)
@@ -806,8 +820,22 @@ module Squared
806
820
  when :exec
807
821
  raise ArgumentError, message('nothing to execute', hint: flag) if list.empty?
808
822
  end
809
- target << val << list.shift
810
- target << list.join(' && ') unless list.empty?
823
+ target << id
824
+ case list.first
825
+ when '--'
826
+ target.merge(list.drop(1))
827
+ when /\A(--|&&)(\s|\z)/
828
+ target.merge(list)
829
+ else
830
+ target << list.shift
831
+ unless list.empty?
832
+ if list.first.start_with?('-')
833
+ target.merge(list)
834
+ else
835
+ target << list.join(' && ')
836
+ end
837
+ end
838
+ end
811
839
  end
812
840
 
813
841
  def append_file(type, target: @session, index: 2, force: false)
@@ -839,13 +867,13 @@ module Squared
839
867
  else
840
868
  Array(val)
841
869
  end.each do |s|
842
- s = "#{s}:#{ver}" if ver && (!s.include?(':') || s.delete_suffix!(':latest'))
870
+ s = tagname s, ver if ver && (!s.include?(':') || s.delete_suffix!(':latest'))
843
871
  target << basic_option('tag', tagname(s))
844
872
  end
845
873
  target
846
874
  end
847
875
 
848
- def filter_ps(flag, from = :'container:ps')
876
+ def filter_ps(flag, meth = nil, from: meth || :'container:ps')
849
877
  no = false
850
878
  status = case flag.to_sym
851
879
  when :start
@@ -879,7 +907,7 @@ module Squared
879
907
  pwd_set(from: from) do
880
908
  index = 1
881
909
  all = option('all', prefix: 'docker')
882
- y = from == :'image:rm' && option('y', prefix: 'docker')
910
+ y = from.to_s.end_with?(':rm') && option('y', prefix: 'docker')
883
911
  filter = env('DOCKER_FILTER', filter).to_s
884
912
  pat = if OptionPartition.pattern?(filter)
885
913
  Regexp.new(filter)
@@ -915,17 +943,17 @@ module Squared
915
943
  puts unless index == 1
916
944
  puts (h + sub_style(aa, theme[:subject])).subhint("created #{e} ago")
917
945
  cols = %w[Tag Status Ports]
918
- cols << case flag
919
- when :connect, :disconnect
920
- 'Networks'
921
- else
922
- 'Size'
923
- end
924
- cols.each do |key|
925
- next if (key == 'Tag' && !dd) || (key == 'Size' && data[key] == '0B')
926
-
927
- puts "#{g + f} #{key}: #{Array(data[key]).join(', ')}" unless data[key].to_s.empty?
928
- end
946
+ .push(case flag
947
+ when :connect, :disconnect
948
+ 'Networks'
949
+ else
950
+ 'Size'
951
+ end)
952
+ .reject do |key|
953
+ (key == 'Tag' && !dd) || (key == 'Size' && data[key] == '0B') || data[key].to_s.empty?
954
+ end
955
+ pad = cols.map(&:size).max
956
+ cols.each { |key| puts "#{g + f} #{key.rjust(pad)}: #{Array(data[key]).join(', ')}" }
929
957
  w = 9 + flag.to_s.size + 4 + ee.size
930
958
  puts g + sub_style(ARG[:BORDER][6] + (ARG[:BORDER][1] * w), theme[:inline])
931
959
  index += 1
@@ -1008,7 +1036,7 @@ module Squared
1008
1036
  cmd = docker_output(ctx, *action)
1009
1037
  case flag
1010
1038
  when :tag
1011
- args = tagjoin @registry, tag
1039
+ args = tagjoin registry, tag
1012
1040
  when :save
1013
1041
  opts = opts.sub_ext('.tar')
1014
1042
  cmd << quote_option('output', File.expand_path(opts))
@@ -1020,8 +1048,7 @@ module Squared
1020
1048
  cmd << opts << '--'
1021
1049
  end
1022
1050
  cmd.merge(Array(out).map { |val| val.split(/\s+/, 2).first })
1023
- cmd << args
1024
- success?(run(cmd), ctx.start_with?('network', 'tag', 'save'))
1051
+ success?(run(cmd << args, { 'NO_COLOR' => 'true' }), ctx.start_with?('network', 'tag', 'save'))
1025
1052
  end
1026
1053
 
1027
1054
  def filetype(val = dockerfile)
@@ -1048,11 +1075,20 @@ module Squared
1048
1075
  args.map { |val| val.chomp(char) }.join(char) unless args.empty?
1049
1076
  end
1050
1077
 
1051
- def tagname(val)
1052
- val = val.split(':').map { |s| charname(s.sub(/^\W+/, '')) }
1078
+ def tagname(*val, max: 128)
1079
+ val = val.compact
1080
+ .join(':')
1081
+ .split(':')
1082
+ .map { |s| charname(s.sub(/^\W+/, '')) }
1053
1083
  ret = val.join(':')
1054
- ret = val.first if val.size > 1 && ret.size > 128
1055
- ret[0..127]
1084
+ return ret unless ret.size > max
1085
+
1086
+ while val.size > 1
1087
+ val.pop
1088
+ s = val.join(':')
1089
+ return s unless s.size > max
1090
+ end
1091
+ ret[0...max]
1056
1092
  end
1057
1093
 
1058
1094
  def dnsname(val)
@@ -1067,6 +1103,10 @@ module Squared
1067
1103
  tag.is_a?(Array) ? tag.first : tag
1068
1104
  end
1069
1105
 
1106
+ def dockerinit
1107
+ { project: self, strict: strict?, explicit: '=', bool: %w[true false 1 0] }
1108
+ end
1109
+
1070
1110
  def emptyargs(list, hint = nil)
1071
1111
  raise ArgumentError, message('unrecognized args', list.join(', '), hint: hint) unless list.empty?
1072
1112
  end