squared 0.8.4 → 0.9.0.pre1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +87 -3
- data/README.md +159 -117
- data/exe/sqd +224 -0
- data/lib/squared/common/base.rb +7 -3
- data/lib/squared/common/format.rb +8 -3
- data/lib/squared/common/host.rb +4 -0
- data/lib/squared/common/prompt.rb +65 -31
- data/lib/squared/common/shell.rb +3 -1
- data/lib/squared/common/system.rb +2 -9
- data/lib/squared/config.rb +3 -3
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +24 -13
- data/lib/squared/workspace/project/base.rb +103 -48
- data/lib/squared/workspace/project/docker.rb +160 -83
- data/lib/squared/workspace/project/git.rb +65 -88
- data/lib/squared/workspace/project/node.rb +28 -25
- data/lib/squared/workspace/project/python.rb +58 -19
- data/lib/squared/workspace/project/ruby.rb +44 -33
- data/lib/squared/workspace/project/support/class.rb +1 -1
- data/lib/squared/workspace/project/support/optionpartition.rb +25 -18
- data/lib/squared/workspace/repo.rb +6 -6
- data/lib/squared/workspace/series.rb +4 -2
- data/squared.gemspec +7 -5
- metadata +21 -5
|
@@ -16,19 +16,19 @@ module Squared
|
|
|
16
16
|
cgroup-parent=b iidfile=p label=q network=b no-cache-filter=b o|output=q platform=q q|quiet
|
|
17
17
|
resource=q secret=qq shm-size=b ssh=qq t|tag=b target=b ulimit=q].freeze,
|
|
18
18
|
bake: %w[print list=q set=qq var=qq].freeze,
|
|
19
|
-
shared: %w[check load no-cache pull push allow=
|
|
20
|
-
|
|
19
|
+
shared: %w[check load no-cache provenance pull push sbom allow=qq call=b? f|file=p metadata-file=p policy=q
|
|
20
|
+
progress=b].freeze
|
|
21
21
|
}.freeze,
|
|
22
22
|
compose: {
|
|
23
|
-
common: %w[all-resources
|
|
23
|
+
common: %w[1 all-resources compatibility dry-run ansi=b env-file=p f|file=p parallel=n profile=b progress=b
|
|
24
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
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
|
-
cap-add=b cap-drop=b entrypoint=q e|env=qq env-from-file=p i|interactive
|
|
31
|
-
|
|
30
|
+
cap-add=b cap-drop=b entrypoint=q e|env=qq env-from-file=p i|interactive l|label=q name=b T|no-tty
|
|
31
|
+
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
|
|
@@ -50,7 +50,7 @@ module Squared
|
|
|
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
52
|
ulimit=q u|user=b userns=b uts=b v|volume=qq volume-driver=b volumes-from=b w|workdir=q].freeze,
|
|
53
|
-
run: %w[d|detach detach-keys=q sig-proxy
|
|
53
|
+
run: %w[d|detach detach-keys=q sig-proxy].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,
|
|
@@ -81,16 +81,17 @@ module Squared
|
|
|
81
81
|
connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=q link=b link-local-ip=q].freeze,
|
|
82
82
|
create: %w[attachable config-only gateway=q ingress internal ipv4 ipv6 aux-address=q config-from=b
|
|
83
83
|
d|driver=b ip-range=q ipam-driver=b ipam-opt=q label=q o|opt=q scope=b subnet=q].freeze,
|
|
84
|
-
disconnect: %w[f|force].freeze
|
|
84
|
+
disconnect: %w[f|force].freeze,
|
|
85
|
+
rm: %w[f|force].freeze
|
|
85
86
|
}.freeze
|
|
86
87
|
}.freeze
|
|
87
88
|
VAL_DOCKER = {
|
|
88
89
|
run: {
|
|
89
90
|
common: %w[source src destination dst target readonly ro].freeze,
|
|
90
|
-
bind: %w[bind-propagation].freeze,
|
|
91
|
+
bind: %w[bind-create-src bind-propagation].freeze,
|
|
91
92
|
volume: %w[volume-subpath volume-nocopy volume-opt].freeze,
|
|
92
93
|
tmpfs: %w[tmpfs-size tmpfs-mode].freeze,
|
|
93
|
-
image: %w[image-
|
|
94
|
+
image: %w[image-subpath].freeze
|
|
94
95
|
}.freeze,
|
|
95
96
|
ls: {
|
|
96
97
|
compose: %w[Name Image Command Service RunningFor Status Ports CreatedAt ExitCode Health ID Labels
|
|
@@ -127,7 +128,8 @@ module Squared
|
|
|
127
128
|
'image' => %i[ls rm pull push tag save inspect history].freeze,
|
|
128
129
|
'container' => %i[attach commit create diff exec inspect kill logs pause restart rm run start stats stop top
|
|
129
130
|
unpause update].freeze,
|
|
130
|
-
'
|
|
131
|
+
'run' => %i[rmi rmd mount volume entrypoint].freeze,
|
|
132
|
+
'network' => %i[connect disconnect create rm].freeze,
|
|
131
133
|
'ls' => nil
|
|
132
134
|
})
|
|
133
135
|
|
|
@@ -139,8 +141,7 @@ module Squared
|
|
|
139
141
|
self.global = nil
|
|
140
142
|
return unless dockerfile(kwargs[:file]).exist?
|
|
141
143
|
|
|
142
|
-
@tag = env('TAG', strict: true,
|
|
143
|
-
ignore: false) || kwargs[:tag] || tagname(@project, @version || 'latest')
|
|
144
|
+
@tag = env('TAG', strict: true, ignore: false) || kwargs[:tag] || tagname(@project, @version || 'latest')
|
|
144
145
|
@context = kwargs[:context]
|
|
145
146
|
@client = kwargs[:client]&.each_with_object([]) do |(key, val), out|
|
|
146
147
|
val = case (key = key.to_s)
|
|
@@ -149,7 +150,7 @@ module Squared
|
|
|
149
150
|
when 'tlscacert', 'tlscert', 'tlskey'
|
|
150
151
|
basepath!(val, type: 'f')
|
|
151
152
|
when 'context', 'host', 'log-level'
|
|
152
|
-
quote_option
|
|
153
|
+
quote_option key, val
|
|
153
154
|
when 'debug', 'tls', 'tlsverify'
|
|
154
155
|
out << key
|
|
155
156
|
next
|
|
@@ -158,7 +159,7 @@ module Squared
|
|
|
158
159
|
end
|
|
159
160
|
@mounts = Array(kwargs[:mounts])
|
|
160
161
|
@secrets = kwargs[:secrets]
|
|
161
|
-
|
|
162
|
+
@registry = tagjoin kwargs[:registry], kwargs[:username]
|
|
162
163
|
@oci = tagjoin kwargs[:oci], kwargs[:username]
|
|
163
164
|
initialize_ref Docker.ref
|
|
164
165
|
initialize_logger kwargs[:log]
|
|
@@ -303,13 +304,22 @@ module Squared
|
|
|
303
304
|
end
|
|
304
305
|
end
|
|
305
306
|
else
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
307
|
+
single = %i[logs diff attach top].freeze
|
|
308
|
+
format_desc action, flag, "opts*,id/name#{if flag == :stats
|
|
309
|
+
'*'
|
|
310
|
+
elsif !single.include?(flag)
|
|
311
|
+
'+'
|
|
312
|
+
end}|:"
|
|
311
313
|
task flag do |_, args|
|
|
312
|
-
|
|
314
|
+
args = args.to_a
|
|
315
|
+
if choice!(args, first: false)
|
|
316
|
+
args.concat(Array(choice_command(:container, multiple: !single.include?(flag))))
|
|
317
|
+
if flag == :rm
|
|
318
|
+
stop = filter_ps(:stop, column: 'ID').select { |id| args.include?(id) }
|
|
319
|
+
container :stop, stop if !stop.empty? && confirm_basic('Stop?', stop.join(', '))
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
container flag, args
|
|
313
323
|
end
|
|
314
324
|
end
|
|
315
325
|
when 'image'
|
|
@@ -358,14 +368,47 @@ module Squared
|
|
|
358
368
|
end
|
|
359
369
|
end
|
|
360
370
|
end
|
|
371
|
+
when 'run'
|
|
372
|
+
format_desc action, flag, 'id|:,opts*'
|
|
373
|
+
task flag, [:id] do |_, args|
|
|
374
|
+
id = if args.id == ':'
|
|
375
|
+
choice_command(:image, multiple: false)
|
|
376
|
+
else
|
|
377
|
+
param_guard(action, flag, args: args, key: :id)
|
|
378
|
+
end
|
|
379
|
+
args = case flag
|
|
380
|
+
when :mount
|
|
381
|
+
mount = []
|
|
382
|
+
loop do
|
|
383
|
+
s = readline("Enter mount ##{mount.size.succ}", force: false)
|
|
384
|
+
break if s.empty?
|
|
385
|
+
|
|
386
|
+
mount << (s.include?('type=') ? s : "type=bind,#{s}")
|
|
387
|
+
end
|
|
388
|
+
mount.map { |val| quote_option('mount', val, double: true) }
|
|
389
|
+
when :volume
|
|
390
|
+
choice_command(:volume, multiple: true, series: true).map do |val|
|
|
391
|
+
basic_option 'volume', val
|
|
392
|
+
end
|
|
393
|
+
when :entrypoint
|
|
394
|
+
["entrypoint=#{shell_quote(readline('Entrypoint', force: true), double: true)}"]
|
|
395
|
+
when :rmi
|
|
396
|
+
%w[rm i t]
|
|
397
|
+
when :rmd
|
|
398
|
+
%w[rm d]
|
|
399
|
+
end + args.extras
|
|
400
|
+
container(:run, args.uniq, id: id)
|
|
401
|
+
end
|
|
361
402
|
when 'network'
|
|
362
|
-
format_desc action, flag, '
|
|
363
|
-
task flag, [:
|
|
364
|
-
|
|
365
|
-
if
|
|
366
|
-
network(flag, args.extras,
|
|
403
|
+
format_desc action, flag, 'name,opts*'
|
|
404
|
+
task flag, [:name] do |_, args|
|
|
405
|
+
name = flag == :create ? param_guard(action, flag, args: args, key: :name) : args.name
|
|
406
|
+
if name
|
|
407
|
+
network(flag, args.extras, name: name)
|
|
408
|
+
elsif flag == :rm
|
|
409
|
+
choice_command :'network:rm'
|
|
367
410
|
else
|
|
368
|
-
choice_command
|
|
411
|
+
choice_command(flag, id: choice_command(:container, force: false), series: true)
|
|
369
412
|
end
|
|
370
413
|
end
|
|
371
414
|
end
|
|
@@ -497,7 +540,7 @@ module Squared
|
|
|
497
540
|
if flag == :publish
|
|
498
541
|
id ||= option('tag', ignore: false) || op.shift || tagmain
|
|
499
542
|
registry ||= option('registry') || op.shift || @oci
|
|
500
|
-
|
|
543
|
+
op.clear(strict: true)
|
|
501
544
|
op << shell_quote(tagjoin(registry, id))
|
|
502
545
|
return unless confirm_command(op.to_s, title: from, target: id)
|
|
503
546
|
else
|
|
@@ -512,10 +555,10 @@ module Squared
|
|
|
512
555
|
if multiple
|
|
513
556
|
op.concat(service) if service
|
|
514
557
|
op.append(delim: true, escape: true, strip: ':')
|
|
515
|
-
|
|
516
|
-
raise ArgumentError, message('no service was selected', hint: flag) unless service
|
|
517
|
-
|
|
558
|
+
elsif service
|
|
518
559
|
append_command(flag, service, op.extras, prompt: '::')
|
|
560
|
+
else
|
|
561
|
+
raise ArgumentError, message('no service was selected', hint: flag)
|
|
519
562
|
end
|
|
520
563
|
end
|
|
521
564
|
end
|
|
@@ -530,6 +573,7 @@ module Squared
|
|
|
530
573
|
list += ct[:create] if rc
|
|
531
574
|
list += ct[:update] if rc ||= flag == :create
|
|
532
575
|
op = OptionPartition.new(opts, list, cmd, args: rc || flag == :exec, **dockerinit)
|
|
576
|
+
option('entrypoint') { |val| op.add_option('entrypoint', val, escape: false, double: true) } if flag == :run
|
|
533
577
|
from = symjoin 'container', flag
|
|
534
578
|
case flag
|
|
535
579
|
when :run, :create, :exec
|
|
@@ -557,23 +601,35 @@ module Squared
|
|
|
557
601
|
end
|
|
558
602
|
end
|
|
559
603
|
case k
|
|
560
|
-
when 'readonly', 'ro'
|
|
561
|
-
out << k
|
|
604
|
+
when 'readonly', 'ro', 'volume-nocopy', 'bind-create-src'
|
|
605
|
+
out << k if %w[bind volume].include?(type)
|
|
562
606
|
next
|
|
563
|
-
when 'source', 'src', 'destination', 'dst', 'target', 'volume-subpath', 'image-
|
|
607
|
+
when 'source', 'src', 'destination', 'dst', 'target', 'volume-subpath', 'image-subpath'
|
|
564
608
|
raise ArgumentError, message('no path value', k, hint: flag) unless v
|
|
565
609
|
|
|
566
|
-
|
|
610
|
+
case k
|
|
611
|
+
when 'source', 'src'
|
|
612
|
+
if type == 'bind'
|
|
613
|
+
v = basepath v
|
|
614
|
+
elsif type == 'tmpfs'
|
|
615
|
+
next
|
|
616
|
+
end
|
|
617
|
+
when 'destination', 'dst', 'target'
|
|
618
|
+
unless v.start_with?('/')
|
|
619
|
+
print_error(Logger::ERROR, "path is not absolute: #{v}", subject: from, hint: k)
|
|
620
|
+
next
|
|
621
|
+
end
|
|
622
|
+
end
|
|
567
623
|
v = shell_quote(v, option: false, force: false) if q == ''
|
|
568
624
|
end
|
|
569
625
|
out << "#{k}=#{q}#{v}#{q}"
|
|
570
626
|
elsif !silent?
|
|
571
|
-
log_message('unrecognized option', subject: from, hint: k)
|
|
627
|
+
puts log_message('unrecognized option', subject: from, hint: k)
|
|
572
628
|
end
|
|
573
629
|
end
|
|
574
630
|
raise TypeError, message('none specified', hint: flag) unless type
|
|
575
631
|
|
|
576
|
-
|
|
632
|
+
op << "--mount type=#{type},#{args.join(',')}"
|
|
577
633
|
end
|
|
578
634
|
end
|
|
579
635
|
append_command(flag, id || tagmain, op.extras)
|
|
@@ -583,7 +639,7 @@ module Squared
|
|
|
583
639
|
op.append(escape: true, strip: ':')
|
|
584
640
|
when :commit
|
|
585
641
|
latest = op.shift || tagmain
|
|
586
|
-
|
|
642
|
+
op << id << latest
|
|
587
643
|
raise ArgumentError, message('unrecognized args', op.join(', '), hint: flag) unless op.empty?
|
|
588
644
|
return unless confirm_command(cmd.to_s, title: from, target: id, as: latest)
|
|
589
645
|
|
|
@@ -604,7 +660,7 @@ module Squared
|
|
|
604
660
|
else
|
|
605
661
|
if op.empty?
|
|
606
662
|
ps, status, no = filter_ps(flag, from: from)
|
|
607
|
-
|
|
663
|
+
op << '--no-stream' if flag == :stats
|
|
608
664
|
list_image(flag, ps, no: no, hint: status, multiple: flag != :attach, from: from) do |img|
|
|
609
665
|
run(cmd.temp(img), from: from)
|
|
610
666
|
end
|
|
@@ -633,11 +689,12 @@ module Squared
|
|
|
633
689
|
op = OptionPartition.new(opts, list, cmd, **dockerinit)
|
|
634
690
|
exception = exception?
|
|
635
691
|
banner = true
|
|
692
|
+
status = false
|
|
636
693
|
from = symjoin 'image', flag
|
|
637
694
|
case flag
|
|
638
695
|
when :ls
|
|
639
696
|
if opts.size == op.size
|
|
640
|
-
index =
|
|
697
|
+
index = -1
|
|
641
698
|
name = nil
|
|
642
699
|
opts.reverse_each do |val|
|
|
643
700
|
next unless (arg = OptionPartition.parse_arg!('name', val))
|
|
@@ -648,8 +705,9 @@ module Squared
|
|
|
648
705
|
end
|
|
649
706
|
list_image(:run, filter: filter, from: from) do |val|
|
|
650
707
|
args = if name
|
|
708
|
+
index += 1
|
|
651
709
|
opts.dup << "name=#{index == 0 ? name : "#{name}-#{index}"}"
|
|
652
|
-
elsif choice!(opts, only: true)
|
|
710
|
+
elsif choice!(opts, empty: true, only: true)
|
|
653
711
|
OptionPartition.strip(readline('Enter arguments', force: false))
|
|
654
712
|
else
|
|
655
713
|
opts
|
|
@@ -659,7 +717,6 @@ module Squared
|
|
|
659
717
|
break
|
|
660
718
|
end
|
|
661
719
|
container(:run, args, id: val)
|
|
662
|
-
index += 1
|
|
663
720
|
end
|
|
664
721
|
return
|
|
665
722
|
end
|
|
@@ -679,16 +736,15 @@ module Squared
|
|
|
679
736
|
banner = false
|
|
680
737
|
end
|
|
681
738
|
when :tag, :save
|
|
682
|
-
found = false
|
|
683
739
|
list_image(flag, filter: filter, from: from) do |val|
|
|
684
740
|
op << val
|
|
685
|
-
|
|
741
|
+
status = true
|
|
686
742
|
if flag == :tag
|
|
687
743
|
op << tagname(project, op.first)
|
|
688
744
|
break
|
|
689
745
|
end
|
|
690
746
|
end
|
|
691
|
-
raise ArgumentError, message('target not specified', hint: flag) unless
|
|
747
|
+
raise ArgumentError, message('target not specified', hint: flag) unless status
|
|
692
748
|
when :pull
|
|
693
749
|
if !id
|
|
694
750
|
id = tagmain
|
|
@@ -699,13 +755,13 @@ module Squared
|
|
|
699
755
|
registry = op.shift
|
|
700
756
|
registry ||= option('registry') || self.registry unless id.include?('/')
|
|
701
757
|
end
|
|
702
|
-
|
|
758
|
+
op << shell_quote(tagjoin(registry, id))
|
|
703
759
|
when :push
|
|
704
760
|
id ||= option('tag', ignore: false) || op.shift || tagmain
|
|
705
761
|
registry ||= option('registry') || op.shift || self.registry
|
|
706
|
-
emptyargs op, flag
|
|
707
762
|
raise ArgumentError, message('username/registry not specified', hint: flag) unless registry
|
|
708
763
|
|
|
764
|
+
op.clear(strict: true)
|
|
709
765
|
uri = shell_quote tagjoin(registry, id)
|
|
710
766
|
op << uri
|
|
711
767
|
img = docker_output 'image tag', id, uri
|
|
@@ -725,16 +781,17 @@ module Squared
|
|
|
725
781
|
op.append(escape: true, strip: ':')
|
|
726
782
|
end
|
|
727
783
|
end
|
|
728
|
-
success?(run(sync: sync, exception: exception, banner: banner, from: from),
|
|
784
|
+
success?(run(sync: sync, exception: exception, banner: banner, from: from), status)
|
|
729
785
|
end
|
|
730
786
|
|
|
731
|
-
def network(flag, opts = [],
|
|
787
|
+
def network(flag, opts = [], name: nil)
|
|
732
788
|
cmd, opts = docker_session('network', flag, opts: opts)
|
|
733
789
|
op = OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, **dockerinit)
|
|
734
790
|
.clear
|
|
735
791
|
from = symjoin 'network', flag
|
|
736
|
-
|
|
737
|
-
|
|
792
|
+
case flag
|
|
793
|
+
when :create, :rm
|
|
794
|
+
op.add_quote(name)
|
|
738
795
|
run(from: from)
|
|
739
796
|
else
|
|
740
797
|
list_image(flag, docker_output('ps -a'), from: from) do |id|
|
|
@@ -752,13 +809,13 @@ module Squared
|
|
|
752
809
|
end
|
|
753
810
|
|
|
754
811
|
def compose?(file = dockerfile)
|
|
755
|
-
return file
|
|
812
|
+
return file.between?(3, 4) if file.is_a?(Numeric)
|
|
756
813
|
|
|
757
814
|
COMPOSEFILE.include?(File.basename(file))
|
|
758
815
|
end
|
|
759
816
|
|
|
760
817
|
def bake?(file = dockerfile)
|
|
761
|
-
return file
|
|
818
|
+
return file.between?(1, 2) if file.is_a?(Numeric)
|
|
762
819
|
|
|
763
820
|
BAKEFILE.include?(File.basename(file))
|
|
764
821
|
end
|
|
@@ -770,11 +827,11 @@ module Squared
|
|
|
770
827
|
val.size > 1 ? val : val.first
|
|
771
828
|
elsif val == true
|
|
772
829
|
DIR_DOCKER.find { |file| exist?(file) }
|
|
773
|
-
elsif val !=
|
|
830
|
+
elsif val != DIR_DOCKER.last
|
|
774
831
|
val
|
|
775
832
|
end
|
|
776
833
|
end
|
|
777
|
-
basepath((@file.is_a?(Array) ? @file.first : @file) ||
|
|
834
|
+
basepath((@file.is_a?(Array) ? @file.first : @file) || DIR_DOCKER.last)
|
|
778
835
|
end
|
|
779
836
|
|
|
780
837
|
private
|
|
@@ -790,7 +847,7 @@ module Squared
|
|
|
790
847
|
yield data
|
|
791
848
|
end
|
|
792
849
|
rescue => e
|
|
793
|
-
|
|
850
|
+
print_error(e, subject: name, hint: 'compose')
|
|
794
851
|
end
|
|
795
852
|
end
|
|
796
853
|
|
|
@@ -873,7 +930,7 @@ module Squared
|
|
|
873
930
|
target
|
|
874
931
|
end
|
|
875
932
|
|
|
876
|
-
def filter_ps(flag,
|
|
933
|
+
def filter_ps(flag, column: nil, from: :'container:ps')
|
|
877
934
|
no = false
|
|
878
935
|
status = case flag.to_sym
|
|
879
936
|
when :start
|
|
@@ -899,6 +956,8 @@ module Squared
|
|
|
899
956
|
end
|
|
900
957
|
cmd = docker_output("#{from.to_s.split(':').first} ps -a",
|
|
901
958
|
*status.map { |s| quote_option('filter', "status=#{s}") })
|
|
959
|
+
return IO.popen(cmd.temp("--format=\"{{.#{column}}}\"")).map(&:chomp) if column
|
|
960
|
+
|
|
902
961
|
[cmd, status, no]
|
|
903
962
|
end
|
|
904
963
|
|
|
@@ -907,15 +966,15 @@ module Squared
|
|
|
907
966
|
pwd_set(from: from) do
|
|
908
967
|
index = 1
|
|
909
968
|
all = option('all', prefix: 'docker')
|
|
910
|
-
y = from
|
|
969
|
+
y = from == :'image:rm' && option('y', prefix: 'docker')
|
|
911
970
|
filter = env('DOCKER_FILTER', filter).to_s
|
|
912
971
|
pat = if OptionPartition.pattern?(filter)
|
|
913
972
|
Regexp.new(filter)
|
|
914
973
|
elsif filter.match?(/[:_-]$/)
|
|
915
974
|
/\b#{Regexp.escape(filter)}/
|
|
916
975
|
else
|
|
917
|
-
|
|
918
|
-
/\b(#{
|
|
976
|
+
names = [dnsname(name), subdomainname(name), tagname(project), tagmain.split(':').first]
|
|
977
|
+
/\b(#{names.join('|')})#{filter.empty? ? '([:_-]|$)' : "[:_-]#{filter}"}/
|
|
919
978
|
end
|
|
920
979
|
IO.popen(cmd.temp('--format=json')).each do |line|
|
|
921
980
|
data = JSON.parse(line)
|
|
@@ -989,18 +1048,22 @@ module Squared
|
|
|
989
1048
|
confirm "#{s} #{sub_style(target, theme[:subject])}#{" as #{sub_style(as, theme[:inline])}" if as}?", 'N'
|
|
990
1049
|
end
|
|
991
1050
|
|
|
992
|
-
def choice_command(flag, *action)
|
|
1051
|
+
def choice_command(flag, *action, id: nil, multiple: nil, series: false, force: true)
|
|
993
1052
|
msg, cmd = case flag
|
|
994
|
-
when :exec
|
|
1053
|
+
when :exec, :container
|
|
995
1054
|
['Choose a container', 'ps -a']
|
|
996
1055
|
when :bake
|
|
997
1056
|
['Choose a target', 'buildx bake --list=type=targets']
|
|
998
|
-
when :connect, :disconnect
|
|
1057
|
+
when :connect, :disconnect, :'network:rm'
|
|
999
1058
|
['Choose a network', 'network ls']
|
|
1000
1059
|
when :service
|
|
1001
1060
|
['Choose a service',
|
|
1002
1061
|
'compose ps -a ' \
|
|
1003
1062
|
'--format="table {{.Service}}\t{{.Name}}\t{{.Image}}\t{{.Command}}\t{{.Status}}\t{{.Ports}}"']
|
|
1063
|
+
when :volume
|
|
1064
|
+
['Choose a volume',
|
|
1065
|
+
'volume ls ' \
|
|
1066
|
+
'--format="table {{.Name}}\t{{.Driver}}\t{{.Mountpoint}}"']
|
|
1004
1067
|
else
|
|
1005
1068
|
['Choose an image',
|
|
1006
1069
|
'images -a ' \
|
|
@@ -1011,28 +1074,40 @@ module Squared
|
|
|
1011
1074
|
puts log_message('none found', subject: name, hint: "docker #{cmd.split(' ', 3)[0, 2].join(' ')}")
|
|
1012
1075
|
return
|
|
1013
1076
|
end
|
|
1014
|
-
|
|
1015
|
-
|
|
1077
|
+
parse = lambda do |list|
|
|
1078
|
+
ret = Array(list).map { |val| val.split(/\s+/, 2).first }.reject(&:empty?)
|
|
1079
|
+
return ret.first if multiple == false
|
|
1080
|
+
|
|
1081
|
+
ret unless ret.empty?
|
|
1082
|
+
end
|
|
1083
|
+
puts "#{"\n" if id && !printfirst?} # #{lines.shift}"
|
|
1016
1084
|
ctx = flag.to_s
|
|
1017
1085
|
case flag
|
|
1018
1086
|
when :run, :exec
|
|
1019
1087
|
values = [['Options', flag == :run], ['Arguments', flag == :exec]]
|
|
1020
1088
|
when :rm, :bake
|
|
1021
1089
|
values = ['Options']
|
|
1022
|
-
multiple = true
|
|
1090
|
+
multiple = true if multiple.nil?
|
|
1023
1091
|
ctx = flag == :rm ? 'image rm' : "buildx bake -f #{shell_quote(dockerfile)}"
|
|
1024
1092
|
when :save
|
|
1025
1093
|
values = [['Output', true], 'Platform']
|
|
1026
|
-
multiple = true
|
|
1094
|
+
multiple = true if multiple.nil?
|
|
1027
1095
|
when :service
|
|
1028
|
-
values = []
|
|
1029
|
-
multiple = true
|
|
1096
|
+
values = ['Options']
|
|
1097
|
+
multiple = true if multiple.nil?
|
|
1030
1098
|
ctx = 'compose'
|
|
1031
1099
|
when :connect, :disconnect
|
|
1032
|
-
values = ['Options', ['Container', true]]
|
|
1100
|
+
values = id ? ['Options'] : ['Options', ['Container', true]]
|
|
1033
1101
|
ctx = "network #{flag}"
|
|
1102
|
+
when :'network:rm'
|
|
1103
|
+
values = ['Options']
|
|
1104
|
+
multiple = true if multiple.nil?
|
|
1105
|
+
ctx = 'network rm'
|
|
1106
|
+
when :container, :image, :volume
|
|
1107
|
+
return parse.call(choice_index(msg, lines, multiple: multiple, series: series, force: force,
|
|
1108
|
+
attempts: force ? 3 : 1))
|
|
1034
1109
|
end
|
|
1035
|
-
out, opts, args = choice_index(msg, lines, multiple: multiple,
|
|
1110
|
+
out, opts, args = choice_index(msg, lines, values: values, multiple: multiple, series: series)
|
|
1036
1111
|
cmd = docker_output(ctx, *action)
|
|
1037
1112
|
case flag
|
|
1038
1113
|
when :tag
|
|
@@ -1047,8 +1122,10 @@ module Squared
|
|
|
1047
1122
|
else
|
|
1048
1123
|
cmd << opts << '--'
|
|
1049
1124
|
end
|
|
1050
|
-
cmd.merge(
|
|
1051
|
-
|
|
1125
|
+
cmd.merge(parse.call(out))
|
|
1126
|
+
cmd << args
|
|
1127
|
+
cmd.merge(Array(id)) if id
|
|
1128
|
+
success?(run(cmd, { 'NO_COLOR' => 'true' }), ctx.start_with?('network', 'tag', 'save'))
|
|
1052
1129
|
end
|
|
1053
1130
|
|
|
1054
1131
|
def filetype(val = dockerfile)
|
|
@@ -1079,7 +1156,7 @@ module Squared
|
|
|
1079
1156
|
val = val.compact
|
|
1080
1157
|
.join(':')
|
|
1081
1158
|
.split(':')
|
|
1082
|
-
.map { |s|
|
|
1159
|
+
.map { |s| subdomainname(s) }
|
|
1083
1160
|
ret = val.join(':')
|
|
1084
1161
|
return ret unless ret.size > max
|
|
1085
1162
|
|
|
@@ -1088,15 +1165,19 @@ module Squared
|
|
|
1088
1165
|
s = val.join(':')
|
|
1089
1166
|
return s unless s.size > max
|
|
1090
1167
|
end
|
|
1091
|
-
ret[
|
|
1168
|
+
ret[...max]
|
|
1092
1169
|
end
|
|
1093
1170
|
|
|
1094
|
-
def dnsname(val)
|
|
1095
|
-
|
|
1171
|
+
def dnsname(val, max: 63, char: nil)
|
|
1172
|
+
ret = val.sub(/^[^a-z]+/i, '')
|
|
1173
|
+
.sub(/[^a-z\d]+$/i, '')
|
|
1174
|
+
.gsub(/[^a-z\d#{char}]+/i, '-')
|
|
1175
|
+
.gsub(/-{2,}/, '-')[...max]
|
|
1176
|
+
char ? ret : ret.downcase
|
|
1096
1177
|
end
|
|
1097
1178
|
|
|
1098
|
-
def
|
|
1099
|
-
val.gsub(
|
|
1179
|
+
def subdomainname(val)
|
|
1180
|
+
dnsname(val, max: 128, char: '.').gsub(/\.{2,}/, '.')
|
|
1100
1181
|
end
|
|
1101
1182
|
|
|
1102
1183
|
def tagmain
|
|
@@ -1104,11 +1185,7 @@ module Squared
|
|
|
1104
1185
|
end
|
|
1105
1186
|
|
|
1106
1187
|
def dockerinit
|
|
1107
|
-
{ project: self, strict: strict?, explicit: '=', bool: %w[true false
|
|
1108
|
-
end
|
|
1109
|
-
|
|
1110
|
-
def emptyargs(list, hint = nil)
|
|
1111
|
-
raise ArgumentError, message('unrecognized args', list.join(', '), hint: hint) unless list.empty?
|
|
1188
|
+
{ project: self, strict: strict?, explicit: '=', bool: %w[1 0 true false] }
|
|
1112
1189
|
end
|
|
1113
1190
|
|
|
1114
1191
|
def anypath?(*args)
|