squared 0.5.4 → 0.5.6

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.
@@ -4,7 +4,7 @@ module Squared
4
4
  module Workspace
5
5
  module Project
6
6
  class Docker < Base
7
- COMPOSEFILE = %w[compose.yaml compose.yml docker-compose.yaml compose.yml docker-compose.yml].freeze
7
+ COMPOSEFILE = %w[compose.yaml compose.yml docker-compose.yaml docker-compose.yml].freeze
8
8
  BAKEFILE = %w[docker-bake.json docker-bake.hcl docker-bake.override.json docker-bake.override.hcl].freeze
9
9
  DIR_DOCKER = (COMPOSEFILE + BAKEFILE).freeze
10
10
  OPT_DOCKER = {
@@ -12,56 +12,57 @@ module Squared
12
12
  tlskey=p].freeze,
13
13
  buildx: {
14
14
  common: %w[builder=b D|debug],
15
- build: %w[load pull push add-host=q annotation=q attest=q build-arg=qq ent=q iidfile=p label=q a-file=p
16
- network=b no-cache-filter=b o|output=q platform=b q|quiet secret=qq shm-size=b ssh=qq t|tag=b
17
- target=b ulimit=q].freeze,
18
- bake: %w[load print pull push list=q metadata-file=p set=q].freeze,
19
- shared: %w[check no-cache allow=q call=b? f|file=p progress=b provenance=q sbom=q].freeze
15
+ build: %w[add-host=q annotation=q attest=q build-arg=qq build-context=qq cache-from=q cache-to=q
16
+ cgroup-parent=b ent=q iidfile=p label=q a-file=p network=b no-cache-filter=b o|output=q platform=b
17
+ q|quiet secret=qq shm-size=b ssh=qq t|tag=b target=b ulimit=q].freeze,
18
+ bake: %w[print list=q set=q].freeze,
19
+ shared: %w[check load no-cache pull push allow=q call=b? f|file=p metadata-file=p progress=b provenance=q
20
+ sbom=q].freeze
20
21
  }.freeze,
21
22
  compose: {
22
- common: %w[all-resources compatibility dry-run ansi|b env-file=p f|file=p parallel=b profile=b progress=b
23
+ common: %w[all-resources compatibility dry-run ansi|b env-file=p f|file=p parallel=n profile=b progress=b
23
24
  project-directory=p p|project-name=e].freeze,
24
- build: %w[check no-cache pull push with-dependencies q|quiet build-arg=qq builder=b m|memory=b
25
- ssh=qq].freeze,
26
- exec: %w[dry-run privileged d|detach e|env=qq index=i T|no-TTY=b? user=e w|workdir=q].freeze,
27
- run: %w[build dry-run no-deps quiet-pull remove-orphans rm P|service-ports use-aliases cap-add=b cap-drop=b
28
- d|detach entrypoint=q e|env=qq i|interactive=b? l|label=q name=b T|no-TTY=b? p|publish=e pull=b
29
- u|user=e v|volume=q w|workdir=q].freeze,
30
- up: %w[y abort-on-container-exit abort-on-container-failure always-recreate-deps attach-dependencies build
31
- d|detach dry-run force-recreate menu no-build no-color no-deps no-log-prefix no-recreate no-start
32
- quiet-pull remove-orphans V|renew-anon-volumes timestamps wait w|watch attach=b exit-code-from=b
33
- no-attach=b pull=b scale=i t|timeout=i wait-timeout=i].freeze
25
+ build: %w[check no-cache print pull push with-dependencies q|quiet build-arg=qq builder=b m|memory=b
26
+ provenance=q sbom=q ssh=qq].freeze,
27
+ exec: %w[d|detach privileged e|env=qq index=i T|no-TTY=b? user=e w|workdir=q].freeze,
28
+ run: %w[build d|detach no-deps q|quiet quiet-build quiet-pull remove-orphans rm P|service-ports use-aliases
29
+ cap-add=b cap-drop=b q e|env=qq env-from-file=p i|interactive=b? l|label=q name=b T|no-TTY=b?
30
+ p|publish=e pull=b u|user=e v|volume=q w|workdir=q].freeze,
31
+ up: %w[abort-on-container-exit abort-on-container-failure always-recreate-deps attach-dependencies build
32
+ d|detach force-recreate menu no-build no-color no-deps no-log-prefix no-recreate no-start quiet-build
33
+ quiet-pull remove-orphans V|renew-anon-volumes timestamps wait w|watch y|yes attach=b
34
+ exit-code-from=b no-attach=b pull=b scale=i t|timeout=i wait-timeout=i].freeze,
35
+ down: %w[remove-orphans v|volumes rmi=b t|timeout=i].freeze
34
36
  }.freeze,
35
37
  container: {
36
38
  create: %w[init i|interactive no-healthcheck oom-kill-disable privileged P|publish-all q|quiet read-only
37
- rm runtime t|tty use-api-socket io-maxbandwidth=b io-maxiops=b add-host=q annotation=q
38
- a|attach=b blkio-weight=i blkio-weight-device=i cap-add=b cap-drop=b cgroup-parent=b cgroupns=b
39
- cidfile=p device=q device-cgroup-rule=q device-read-bps=q device-read-iops=q device-write-bps=q
39
+ rm runtime t|tty use-api-socket io-maxbandwidth=b io-maxiops=b add-host=q annotation=q a|attach=b
40
+ blkio-weight=i blkio-weight-device=i cap-add=b cap-drop=b cgroup-parent=b cgroupns=b cidfile=p
41
+ device=q device-cgroup-rule=q device-read-bps=q device-read-iops=q device-write-bps=q
40
42
  device-write-iops=q disable-content-trust=b? dns=e dns-option=e dns-search=e domainname=b
41
- entrypoint=q e|env=qq env-file=p expose=e gpus=q group-add=b health-cmd=q health-interval=b
42
- health-retries=i health-start-interval=b health-start-period=b health-timeout=b h|hostname=e ip=b
43
- ip6=e ipc=b isolation=b kernel-memory=b l|label=q label-file=p link=b link-local-ip=b
44
- log-driver=b log-opt=q mac-address=e m|memory=b memory-reservation=b memory-swap=n
45
- memory-swappiness=n mount=qq name=b network=b network-alias=b oom-score-adj=b pid=b pids-limit=n
46
- platform=b p|publish=e pull=b restart=b runtime=b security-opt=q shm-size=b stop-signal=b
47
- stop-timeout=i storage-opt=q sysctl=q tmpfs=q ulimit=q u|user=b userns=b uts=b v|volume=q
48
- volume-driver=b volumes-from=b w|workdir=q].freeze,
43
+ entrypoint=q e|env=qq env-file=p expose=e gpus=q group-add=b health-cmd=q health-interval=b ip6=e
44
+ ipc=b isolation=b kernel-memory=b l|label=q label-file=p link=b link-local-ip=b log-driver=b
45
+ log-opt=q mac-address=e m|memory=b memory-reservation=b memory-swap=n memory-swappiness=n
46
+ mount=qq name=b network=b network-alias=b oom-score-adj=b pid=b pids-limit=n platform=b
47
+ p|publish=e pull=b restart=b runtime=b security-opt=q shm-size=b stop-signal=b stop-timeout=i
48
+ storage-opt=q sysctl=q tmpfs=q ulimit=q u|user=b userns=b uts=b v|volume=q volume-driver=b
49
+ volumes-from=b w|workdir=q].freeze,
49
50
  run: %w[d|detach detach-keys=q sig-proxy=b?].freeze,
50
- exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p user=e
51
- w|workdir=q].freeze,
52
51
  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
53
52
  cpuset-cpus=b cpuset-mems=b m|memory=b memory-reservation=b memory-swap=b pids-limit=n
54
53
  restart=q].freeze,
54
+ exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p user=e
55
+ w|workdir=q].freeze,
55
56
  commit: %w[a|author=q c|change=q m|message=q pause=b?].freeze,
56
57
  inspect: %w[s|size f|format=q].freeze,
57
58
  start: %w[a|attach i|interactive detach-keys=q].freeze,
58
59
  stop: %w[s|signal=b t|time=i t|timeout=i].freeze,
59
60
  restart: %w[s|signal=b t|time=i t|timeout=i].freeze,
60
61
  kill: %w[s|signal=b].freeze,
61
- stats: %w[no-trunc format|q].freeze
62
+ stats: %w[a|all no-stream no-trunc format|q].freeze
62
63
  }.freeze,
63
64
  image: {
64
- list: %w[a|all digests no-trunc f|filter=q format=q].freeze,
65
+ list: %w[a|all q|quiet digests no-trunc tree f|filter=q format=q].freeze,
65
66
  push: %w[a|all-tags disable-content-trust=b? platform=b q|quiet].freeze,
66
67
  rm: %w[f|force no-prune platform=b].freeze,
67
68
  save: %w[o|output=p platform=b].freeze
@@ -96,7 +97,7 @@ module Squared
96
97
 
97
98
  subtasks({
98
99
  'build' => %i[tag context].freeze,
99
- 'compose' => %i[build run exec up].freeze,
100
+ 'compose' => %i[build run exec up down].freeze,
100
101
  'bake' => %i[build check].freeze,
101
102
  'image' => %i[list rm push tag save].freeze,
102
103
  'container' => %i[run create exec update commit inspect diff start stop restart pause unpause top stats kill
@@ -147,11 +148,11 @@ module Squared
147
148
  end
148
149
  end
149
150
  when 'bake'
150
- next unless bake?
151
+ break unless bake?
151
152
 
152
153
  case flag
153
154
  when :build
154
- format_desc action, flag, ':?,opts*,target*,context?'
155
+ format_desc action, flag, 'opts*,target*,context?|:'
155
156
  task flag do |_, args|
156
157
  args = args.to_a
157
158
  if args.first == ':'
@@ -168,16 +169,16 @@ module Squared
168
169
  end
169
170
  end
170
171
  when 'compose'
171
- next unless compose?
172
+ break unless compose?
172
173
 
173
174
  case flag
174
- when :build, :up
175
- format_desc action, flag, 'opts*,service*'
175
+ when :build, :up, :down
176
+ format_desc action, flag, 'opts*,service*|:'
176
177
  task flag do |_, args|
177
178
  compose! flag, args.to_a
178
179
  end
179
180
  when :exec, :run
180
- format_desc action, flag, "service,command#{flag == :exec ? '' : '?'}|:,args*,opts*"
181
+ format_desc action, flag, "service|:,command#{flag == :exec ? '' : '?'}|::,args*,opts*"
181
182
  task flag, [:service] do |_, args|
182
183
  service = param_guard(action, flag, args: args, key: :service)
183
184
  compose!(flag, args.extras, service: service)
@@ -186,7 +187,7 @@ module Squared
186
187
  when 'container'
187
188
  case flag
188
189
  when :exec, :commit
189
- format_desc(action, flag, flag == :exec ? 'id/name,opts*,args+' : 'id/name,tag?,opts*')
190
+ format_desc(action, flag, flag == :exec ? 'id/name,opts*,args+|:' : 'id/name,tag?,opts*')
190
191
  task flag, [:id] do |_, args|
191
192
  if flag == :exec && !args.id
192
193
  choice_command flag
@@ -196,7 +197,7 @@ module Squared
196
197
  end
197
198
  end
198
199
  when :run, :create
199
- format_desc action, flag, 'image,opts*,args*'
200
+ format_desc action, flag, 'image,opts*,args*|:'
200
201
  task flag, [:image] do |_, args|
201
202
  if args.image
202
203
  container(flag, args.extras, id: args.image)
@@ -222,7 +223,8 @@ module Squared
222
223
  format_desc(action, flag, case flag
223
224
  when :rm, :save then 'id*,opts*'
224
225
  when :tag then 'version?'
225
- else 'opts*,args*' end)
226
+ else 'opts*,args*'
227
+ end)
226
228
  task flag do |_, args|
227
229
  args = args.to_a
228
230
  if args.empty? && flag != :list
@@ -259,12 +261,11 @@ module Squared
259
261
 
260
262
  ret = docker_session
261
263
  if from == :run
262
- case (n = filetype)
263
- when 1, 2
264
+ if bake?(n = filetype)
264
265
  ret << 'buildx' << 'bake'
265
266
  append_file n
266
267
  from = :bake
267
- when 3, 4
268
+ elsif compose?(n)
268
269
  ret << 'compose' << 'build'
269
270
  append_file n
270
271
  from = :compose
@@ -335,7 +336,7 @@ module Squared
335
336
  op.push(val)
336
337
  end
337
338
  end
338
- op.append(args, escape: true)
339
+ op.append(args, escape: true, strip: /^:/)
339
340
  contextdir context if context
340
341
  end
341
342
  end
@@ -348,15 +349,27 @@ module Squared
348
349
  op = OptionPartition.new(opts, OPT_DOCKER[:compose][:common], cmd, project: self)
349
350
  append_file filetype unless op.arg?('f', 'file')
350
351
  op << flag
351
- op.parse(OPT_DOCKER[:compose][flag])
352
- from = :"compose:#{flag}"
353
- case flag
354
- when :build, :up
355
- op.append(escape: true)
356
- when :exec, :run
357
- append_command flag, service, op.extras
352
+ op.parse(OPT_DOCKER[:compose].fetch(flag, []))
353
+ multiple = case flag
354
+ when :build, :up, :down then true
355
+ else false
356
+ end
357
+ if op.remove(':') || service == ':'
358
+ keys = Set.new
359
+ read_composefile('services', target: op.values_of('f', 'file')) { |data| keys.merge(data.keys) }
360
+ service = unless keys.empty?
361
+ choice_index('Add services', keys, multiple: multiple, force: !multiple,
362
+ attempts: multiple ? 1 : 5)
363
+ end
358
364
  end
359
- run(from: from)
365
+ if multiple
366
+ op.concat(service) if service
367
+ op.append(delim: true, escape: true, strip: /^:/)
368
+ else
369
+ raise_error('no services were found', hint: flag) unless service
370
+ append_command(flag, service, op.extras, prompt: '::')
371
+ end
372
+ run(from: :"compose:#{flag}")
360
373
  end
361
374
 
362
375
  def container(flag, opts = [], id: nil)
@@ -388,10 +401,10 @@ module Squared
388
401
  elsif all.include?(k)
389
402
  unless type
390
403
  run.each_pair do |key, val|
391
- if val.include?(k)
392
- type = key.to_s unless key == :common
393
- break
394
- end
404
+ next unless val.include?(k)
405
+
406
+ type = key.to_s unless key == :common
407
+ break
395
408
  end
396
409
  end
397
410
  case k
@@ -414,7 +427,7 @@ module Squared
414
427
  append_command(flag, id || tagmain, op.extras)
415
428
  when :update
416
429
  raise_error('missing container', hint: flag) if op.empty?
417
- op.append(escape: true)
430
+ op.append(escape: true, strip: /^:/)
418
431
  when :commit
419
432
  latest = op.shift || tagmain
420
433
  cmd << id << latest
@@ -467,7 +480,7 @@ module Squared
467
480
  end
468
481
  return
469
482
  else
470
- op.append(escape: true)
483
+ op.append(escape: true, strip: /^:/)
471
484
  end
472
485
  end
473
486
  run(from: from)
@@ -544,7 +557,7 @@ module Squared
544
557
 
545
558
  def network(flag, opts = [], target: nil)
546
559
  cmd, opts = docker_session('network', flag, opts: opts)
547
- op = OptionPartition.new(opts, OPT_DOCKER[:network][flag], cmd, project: self)
560
+ op = OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, project: self)
548
561
  op.clear
549
562
  from = :"network:#{flag}"
550
563
  list_image(flag, docker_output('ps -a'), from: from) do |img|
@@ -561,10 +574,14 @@ module Squared
561
574
  end
562
575
 
563
576
  def compose?(file = dockerfile)
577
+ return file == 3 || file == 4 if file.is_a?(Numeric)
578
+
564
579
  COMPOSEFILE.include?(File.basename(file))
565
580
  end
566
581
 
567
582
  def bake?(file = dockerfile)
583
+ return file == 1 || file == 2 if file.is_a?(Numeric)
584
+
568
585
  BAKEFILE.include?(File.basename(file))
569
586
  end
570
587
 
@@ -585,6 +602,21 @@ module Squared
585
602
 
586
603
  private
587
604
 
605
+ def read_composefile(*keys, target: nil)
606
+ require 'yaml'
607
+ target = ENV['COMPOSE_FILE']&.split(workspace.windows? ? ';' : ':') if !target || target.empty?
608
+ Array(target || dockerfile).each do |val|
609
+ doc = YAML.load_file(path + val)
610
+ if keys.empty?
611
+ yield doc
612
+ elsif (data = doc.dig(*keys))
613
+ yield data
614
+ end
615
+ rescue StandardError => e
616
+ log.debug e
617
+ end
618
+ end
619
+
588
620
  def docker_session(*cmd, opts: nil)
589
621
  return session('docker', *cmd) unless opts
590
622
 
@@ -597,9 +629,9 @@ module Squared
597
629
  session('docker', *cmd, main: false, options: false, **kwargs)
598
630
  end
599
631
 
600
- def append_command(flag, val, list, target: @session)
601
- if list.delete(':')
602
- list << readline('Enter command [args]', force: true)
632
+ def append_command(flag, val, list, target: @session, prompt: ':')
633
+ if list.delete(prompt)
634
+ list << readline('Enter command [args]', force: flag == :exec)
603
635
  elsif (args = env('DOCKER_ARGS'))
604
636
  list << args
605
637
  end
@@ -616,13 +648,22 @@ module Squared
616
648
  end
617
649
 
618
650
  def append_file(type, target: @session)
619
- return unless type == 2 || type == 4 || @file.is_a?(Array)
651
+ return if ENV['COMPOSE_FILE'] && compose?(type)
620
652
 
653
+ unless @file.is_a?(Array)
654
+ case type
655
+ when 2, 4
656
+ return
657
+ when 3
658
+ return unless COMPOSEFILE.map { |val| path + val }.select(&:exist?).size > 1
659
+ end
660
+ end
621
661
  files = Array(@file).map { |val| quote_option('file', path + val) }
622
662
  if target.is_a?(Set)
623
- target.merge(files)
663
+ opts = target.to_a.insert(2, *files)
664
+ target.clear.merge(opts)
624
665
  else
625
- target.concat(files)
666
+ target.insert(2, *files)
626
667
  end
627
668
  end
628
669
 
@@ -788,7 +829,7 @@ module Squared
788
829
  bake?(val) ? 1 : 2
789
830
  when '.yml', '.yaml'
790
831
  if compose?(val)
791
- path.children.any? { |file| bake?(file) } ? 1 : 3
832
+ @only&.include?('compose') || path.children.none? { |file| bake?(file) } ? 3 : 1
792
833
  else
793
834
  4
794
835
  end