squared 0.8.2 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +111 -0
- data/README.md +10 -10
- data/lib/squared/common/base.rb +8 -0
- data/lib/squared/common/format.rb +2 -1
- data/lib/squared/common/host.rb +35 -0
- data/lib/squared/common/prompt.rb +11 -6
- data/lib/squared/common/shell.rb +13 -12
- data/lib/squared/common/utils.rb +7 -4
- data/lib/squared/common.rb +1 -0
- data/lib/squared/config.rb +1 -2
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +5 -27
- data/lib/squared/workspace/project/base.rb +59 -19
- data/lib/squared/workspace/project/docker.rb +180 -126
- data/lib/squared/workspace/project/git.rb +363 -174
- data/lib/squared/workspace/project/node.rb +53 -22
- data/lib/squared/workspace/project/python.rb +52 -35
- data/lib/squared/workspace/project/ruby.rb +24 -25
- data/lib/squared/workspace/project/support/optionpartition.rb +121 -57
- data/lib/squared/workspace/repo.rb +5 -7
- data/lib/squared/workspace/series.rb +2 -2
- metadata +3 -2
|
@@ -13,34 +13,35 @@ module Squared
|
|
|
13
13
|
buildx: {
|
|
14
14
|
common: %w[builder=b D|debug],
|
|
15
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 iidfile=p label=q network=b no-cache-filter=b o|output=q platform=q
|
|
17
|
-
q
|
|
18
|
-
bake: %w[print list=q set=
|
|
19
|
-
shared: %w[check load no-cache pull push allow=q call=b? f|file=p metadata-file=p progress=b
|
|
20
|
-
sbom=q].freeze
|
|
16
|
+
cgroup-parent=b iidfile=p label=q network=b no-cache-filter=b o|output=q platform=q q|quiet
|
|
17
|
+
resource=q secret=qq shm-size=b ssh=qq t|tag=b target=b ulimit=q].freeze,
|
|
18
|
+
bake: %w[print list=q set=qq var=qq].freeze,
|
|
19
|
+
shared: %w[check load no-cache pull push allow=q call=b? f|file=p metadata-file=p policy=q progress=b
|
|
20
|
+
provenance=q sbom=q].freeze
|
|
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=
|
|
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-
|
|
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-
|
|
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
|
|
35
35
|
exit-code-from=b no-attach=b pull=b scale=i t|timeout=i wait-timeout=i].freeze,
|
|
36
36
|
down: %w[remove-orphans v|volumes rmi=b t|timeout=i].freeze,
|
|
37
|
-
publish: %w[app resolve-image-digests with-env y|yes oci-version=b].freeze
|
|
37
|
+
publish: %w[app resolve-image-digests with-env y|yes oci-version=b].freeze,
|
|
38
|
+
logs: %w[dry-run f|follow no-color no-log-prefix t|timestamps index=i since=q n|tail=b until=q].freeze
|
|
38
39
|
}.freeze,
|
|
39
40
|
container: {
|
|
40
41
|
create: %w[init i|interactive no-healthcheck oom-kill-disable privileged P|publish-all q|quiet read-only
|
|
41
|
-
rm t|tty use-api-socket add-host=q annotation=q a|attach=b blkio-weight=i
|
|
42
|
-
cap-add=b cap-drop=b cgroup-parent=b cgroupns=b cidfile=p device=q
|
|
43
|
-
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
|
|
44
45
|
dns=q dns-option=q dns-search=q domainname=b entrypoint=q e|env=qq env-file=p expose=q gpus=q
|
|
45
46
|
group-add=b health-cmd=q health-interval=b health-retries=i health-start-interval=q
|
|
46
47
|
health-start-period=q health-timeout=q hostname=q io-maxbandwidth=b io-maxiops=b ip=b ip6=q ipc=b
|
|
@@ -48,26 +49,28 @@ module Squared
|
|
|
48
49
|
m|memory=b memory-reservation=b memory-swap=n memory-swappiness=n mount=qq name=b network=b
|
|
49
50
|
network-alias=b oom-score-adj=b pid=b pids-limit=n platform=q p|publish=q pull=b restart=b
|
|
50
51
|
runtime=b security-opt=q shm-size=b stop-signal=b stop-timeout=i storage-opt=q sysctl=q tmpfs=q
|
|
51
|
-
ulimit=q u|user=b userns=b uts=b v|volume=
|
|
52
|
+
ulimit=q u|user=b userns=b uts=b v|volume=qq volume-driver=b volumes-from=b w|workdir=q].freeze,
|
|
52
53
|
run: %w[d|detach detach-keys=q sig-proxy=b?].freeze,
|
|
53
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
|
|
54
55
|
cpuset-cpus=b cpuset-mems=b m|memory=b memory-reservation=b memory-swap=n pids-limit=n
|
|
55
56
|
restart=q].freeze,
|
|
56
|
-
exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p u|user=
|
|
57
|
+
exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p u|user=b
|
|
57
58
|
w|workdir=q].freeze,
|
|
58
|
-
|
|
59
|
+
rm: %w[f|force l|link v|volumes].freeze,
|
|
60
|
+
commit: %w[no-pause a|author=q c|change=q m|message=q].freeze,
|
|
61
|
+
logs: %w[details f|follow t|timestamps since=q n|tail=b until=q].freeze,
|
|
59
62
|
inspect: %w[s|size f|format=q].freeze,
|
|
60
63
|
start: %w[a|attach i|interactive detach-keys=q].freeze,
|
|
61
64
|
stop: %w[s|signal=b t|timeout=i].freeze,
|
|
62
65
|
restart: %w[s|signal=b t|timeout=i].freeze,
|
|
63
66
|
kill: %w[s|signal=b].freeze,
|
|
64
67
|
stats: %w[a|all no-stream no-trunc format|q].freeze,
|
|
65
|
-
attach: %w[no-stdin detach-keys=q sig-proxy
|
|
68
|
+
attach: %w[no-stdin detach-keys=q sig-proxy].freeze
|
|
66
69
|
}.freeze,
|
|
67
70
|
image: {
|
|
68
71
|
common: %w[platform=q].freeze,
|
|
69
72
|
inspect: %w[f|format].freeze,
|
|
70
|
-
history: %w[f|format no-trunc q|quiet H|human
|
|
73
|
+
history: %w[f|format no-trunc q|quiet H|human].freeze,
|
|
71
74
|
ls: %w[a|all digests no-trunc q|quiet tree f|filter=q format=q].freeze,
|
|
72
75
|
pull: %w[a|all-tags q|quiet].freeze,
|
|
73
76
|
push: %w[a|all-tags q|quiet].freeze,
|
|
@@ -106,6 +109,10 @@ module Squared
|
|
|
106
109
|
[].freeze
|
|
107
110
|
end
|
|
108
111
|
|
|
112
|
+
def bannerargs
|
|
113
|
+
%i[context registry tag].freeze
|
|
114
|
+
end
|
|
115
|
+
|
|
109
116
|
def config?(val)
|
|
110
117
|
return false unless (val = as_path(val))
|
|
111
118
|
|
|
@@ -115,46 +122,43 @@ module Squared
|
|
|
115
122
|
|
|
116
123
|
subtasks({
|
|
117
124
|
'build' => %i[tag context].freeze,
|
|
118
|
-
'compose' => %i[build create publish run exec up down service].freeze,
|
|
125
|
+
'compose' => %i[build create publish run exec up down logs service].freeze,
|
|
119
126
|
'bake' => %i[build compose check].freeze,
|
|
120
127
|
'image' => %i[ls rm pull push tag save inspect history].freeze,
|
|
121
|
-
'container' => %i[attach commit create diff exec inspect kill pause restart rm run start stats stop top
|
|
128
|
+
'container' => %i[attach commit create diff exec inspect kill logs pause restart rm run start stats stop top
|
|
122
129
|
unpause update].freeze,
|
|
123
130
|
'network' => %i[connect disconnect create].freeze,
|
|
124
131
|
'ls' => nil
|
|
125
132
|
})
|
|
126
133
|
|
|
127
134
|
attr_reader :context
|
|
128
|
-
attr_accessor :tag
|
|
135
|
+
attr_accessor :registry, :tag
|
|
129
136
|
|
|
130
|
-
def initialize(*,
|
|
137
|
+
def initialize(*, **kwargs)
|
|
131
138
|
super
|
|
132
139
|
self.global = nil
|
|
133
140
|
return unless dockerfile(kwargs[:file]).exist?
|
|
134
141
|
|
|
135
|
-
@tag =
|
|
142
|
+
@tag = env('TAG', strict: true,
|
|
143
|
+
ignore: false) || kwargs[:tag] || tagname(@project, @version || 'latest')
|
|
136
144
|
@context = kwargs[:context]
|
|
137
|
-
@client =
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
end
|
|
153
|
-
opts unless opts.empty?
|
|
154
|
-
end
|
|
155
|
-
@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])
|
|
156
160
|
@secrets = kwargs[:secrets]
|
|
157
|
-
|
|
161
|
+
self.registry = tagjoin kwargs[:registry], kwargs[:username]
|
|
158
162
|
@oci = tagjoin kwargs[:oci], kwargs[:username]
|
|
159
163
|
initialize_ref Docker.ref
|
|
160
164
|
initialize_logger kwargs[:log]
|
|
@@ -227,7 +231,7 @@ module Squared
|
|
|
227
231
|
format_desc action, flag, 'opts*,target*,context?|:'
|
|
228
232
|
task flag do |_, args|
|
|
229
233
|
args = args.to_a
|
|
230
|
-
if args
|
|
234
|
+
if choice!(args)
|
|
231
235
|
choice_command :bake
|
|
232
236
|
else
|
|
233
237
|
buildx(:bake, args, from: (:'buildx:bake' if flag == :compose))
|
|
@@ -251,14 +255,14 @@ module Squared
|
|
|
251
255
|
compose_(flag, args.extras, service: service)
|
|
252
256
|
end
|
|
253
257
|
when :service
|
|
254
|
-
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
|
|
255
259
|
format_desc(action, flag, cmds, arg: nil, after: 'name+|:')
|
|
256
260
|
task flag, [:command] do |_, args|
|
|
257
261
|
cmd = param_guard(action, flag, args: args, key: :command)
|
|
258
262
|
raise ArgumentError, message('unrecognized command', hint: cmd) unless cmds.include?(cmd)
|
|
259
263
|
|
|
260
264
|
service = args.extras
|
|
261
|
-
if service
|
|
265
|
+
if choice!(service)
|
|
262
266
|
choice_command flag, cmd
|
|
263
267
|
else
|
|
264
268
|
compose_(flag, [cmd], service: service.empty? || service)
|
|
@@ -299,7 +303,11 @@ module Squared
|
|
|
299
303
|
end
|
|
300
304
|
end
|
|
301
305
|
else
|
|
302
|
-
format_desc action, flag, "opts*,id/name#{
|
|
306
|
+
format_desc action, flag, "opts*,id/name#{case flag
|
|
307
|
+
when :stats then '*'
|
|
308
|
+
when :logs, :diff, :attach, :top then nil
|
|
309
|
+
else '+'
|
|
310
|
+
end}"
|
|
303
311
|
task flag do |_, args|
|
|
304
312
|
container flag, args.to_a
|
|
305
313
|
end
|
|
@@ -307,11 +315,13 @@ module Squared
|
|
|
307
315
|
when 'image'
|
|
308
316
|
case flag
|
|
309
317
|
when :push
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
format_desc action, flag, 'tag?,registry/username?,opts*'
|
|
318
|
+
format_desc action, flag, 'tag?,registry/username?|:,opts*'
|
|
313
319
|
task flag do |_, args|
|
|
314
|
-
|
|
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)
|
|
315
325
|
end
|
|
316
326
|
when :pull
|
|
317
327
|
format_desc action, flag, 'tag,registry/username?,opts*'
|
|
@@ -411,19 +421,13 @@ module Squared
|
|
|
411
421
|
when String
|
|
412
422
|
ret << quote_option('secret', @secrets, double: true)
|
|
413
423
|
when Hash
|
|
414
|
-
|
|
424
|
+
%i[file env].each do |key|
|
|
415
425
|
ret.merge(Array(@secrets[key]).map { |arg| quote_option('secret', "type=#{key},#{arg}", double: true) })
|
|
416
426
|
end
|
|
417
|
-
append.call(:file)
|
|
418
|
-
append.call(:env)
|
|
419
427
|
else
|
|
420
428
|
ret.merge(Array(@secrets).map { |arg| quote_option('secret', arg) })
|
|
421
429
|
end
|
|
422
|
-
|
|
423
|
-
append_tag val
|
|
424
|
-
elsif !session_arg?('t', 'tag')
|
|
425
|
-
append_tag tag
|
|
426
|
-
end
|
|
430
|
+
append_tag option('tag', ignore: false) or session_arg?('t', 'tag') ? nil : tag
|
|
427
431
|
append_context
|
|
428
432
|
when :bake, :compose
|
|
429
433
|
option(from == :bake ? 'target' : 'service', ignore: false) { |val| ret.merge(split_escape(val).quote!) }
|
|
@@ -432,18 +436,18 @@ module Squared
|
|
|
432
436
|
end
|
|
433
437
|
|
|
434
438
|
def buildx(flag, opts = [], tag: nil, context: nil, from: nil)
|
|
439
|
+
bx = OPT_DOCKER[:buildx]
|
|
435
440
|
if flag == :bake && context&.match?(%r{^["']?(https?|git)://}i)
|
|
436
|
-
shared =
|
|
441
|
+
shared = bx[:shared].dup.push('f|file=q')
|
|
437
442
|
shared.delete('f|file=p')
|
|
438
443
|
end
|
|
439
444
|
cmd, opts = docker_session('buildx', opts: opts)
|
|
440
|
-
|
|
441
|
-
op = OptionPartition.new(opts, data[:common], cmd, project: self, strict: strict?)
|
|
445
|
+
op = OptionPartition.new(opts, bx[:common], cmd, **dockerinit)
|
|
442
446
|
op.append(flag, quote: false)
|
|
443
|
-
.parse(
|
|
447
|
+
.parse(bx[flag == :bake ? :bake : :build] + (shared || bx[:shared]))
|
|
444
448
|
case flag
|
|
445
449
|
when :build, :context
|
|
446
|
-
append_tag
|
|
450
|
+
append_tag tag || option('tag', ignore: false) || self.tag
|
|
447
451
|
if shared
|
|
448
452
|
op.add_quote(context, preserve: false)
|
|
449
453
|
else
|
|
@@ -451,6 +455,10 @@ module Squared
|
|
|
451
455
|
end
|
|
452
456
|
when :bake
|
|
453
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
|
|
454
462
|
unless op.empty?
|
|
455
463
|
if !context && op.size > 1 && exist?(op.last, type: 'd')
|
|
456
464
|
pat = /\btarget\s+"#{Regexp.escape(op.last)}"/
|
|
@@ -460,7 +468,7 @@ module Squared
|
|
|
460
468
|
context = basepath context
|
|
461
469
|
op.each { |name| op.add_option('set', "#{name}.context=#{context}", escape: false) }
|
|
462
470
|
end
|
|
463
|
-
op.append(escape: true, strip:
|
|
471
|
+
op.append(escape: true, strip: ':', clear: true)
|
|
464
472
|
end
|
|
465
473
|
end
|
|
466
474
|
op.clear(pass: false)
|
|
@@ -472,7 +480,7 @@ module Squared
|
|
|
472
480
|
if flag == :service
|
|
473
481
|
command = opts.first
|
|
474
482
|
if service == true
|
|
475
|
-
cmd, status = filter_ps
|
|
483
|
+
cmd, status = filter_ps(command, from: from)
|
|
476
484
|
lines = IO.popen(cmd.temp('--services')).map(&:strip).reject(&:empty?)
|
|
477
485
|
return list_empty(hint: status) if lines.empty?
|
|
478
486
|
|
|
@@ -481,10 +489,11 @@ module Squared
|
|
|
481
489
|
docker_session('compose', command, '--', *service)
|
|
482
490
|
else
|
|
483
491
|
cmd, opts = docker_session('compose', opts: opts)
|
|
484
|
-
|
|
492
|
+
cp = OPT_DOCKER[:compose]
|
|
493
|
+
op = OptionPartition.new(opts, cp[:common], cmd, **dockerinit)
|
|
485
494
|
append_file(filetype, force: flag == :publish) unless op.arg?('f', 'file')
|
|
486
495
|
op << flag
|
|
487
|
-
op.parse(
|
|
496
|
+
op.parse(cp.fetch(flag, []))
|
|
488
497
|
if flag == :publish
|
|
489
498
|
id ||= option('tag', ignore: false) || op.shift || tagmain
|
|
490
499
|
registry ||= option('registry') || op.shift || @oci
|
|
@@ -502,7 +511,7 @@ module Squared
|
|
|
502
511
|
end
|
|
503
512
|
if multiple
|
|
504
513
|
op.concat(service) if service
|
|
505
|
-
op.append(delim: true, escape: true, strip:
|
|
514
|
+
op.append(delim: true, escape: true, strip: ':')
|
|
506
515
|
else
|
|
507
516
|
raise ArgumentError, message('no service was selected', hint: flag) unless service
|
|
508
517
|
|
|
@@ -515,18 +524,19 @@ module Squared
|
|
|
515
524
|
|
|
516
525
|
def container(flag, opts = [], id: nil)
|
|
517
526
|
cmd, opts = docker_session('container', flag, opts: opts)
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
list
|
|
521
|
-
list +=
|
|
522
|
-
|
|
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)
|
|
523
533
|
from = symjoin 'container', flag
|
|
524
534
|
case flag
|
|
525
535
|
when :run, :create, :exec
|
|
526
536
|
if rc && !op.arg?('mount')
|
|
527
537
|
all = collect_hash VAL_DOCKER[:run]
|
|
528
538
|
delim = Regexp.new(",\\s*(?=#{all.join('|')})")
|
|
529
|
-
|
|
539
|
+
@mounts.each do |val|
|
|
530
540
|
type = nil
|
|
531
541
|
args = val.split(delim).each_with_object([]) do |opt, out|
|
|
532
542
|
k, v, q = OptionPartition.parse_option(opt)
|
|
@@ -570,14 +580,14 @@ module Squared
|
|
|
570
580
|
when :update, :inspect
|
|
571
581
|
raise ArgumentError, message('missing container', hint: flag) if op.empty?
|
|
572
582
|
|
|
573
|
-
op.append(escape: true, strip:
|
|
583
|
+
op.append(escape: true, strip: ':')
|
|
574
584
|
when :commit
|
|
575
585
|
latest = op.shift || tagmain
|
|
576
586
|
cmd << id << latest
|
|
577
587
|
raise ArgumentError, message('unrecognized args', op.join(', '), hint: flag) unless op.empty?
|
|
578
588
|
return unless confirm_command(cmd.to_s, title: from, target: id, as: latest)
|
|
579
589
|
|
|
580
|
-
registry = option('registry') ||
|
|
590
|
+
registry = option('registry') || self.registry
|
|
581
591
|
run(from: from, exception: registry.nil? ? exception? : true)
|
|
582
592
|
return unless registry
|
|
583
593
|
|
|
@@ -593,23 +603,34 @@ module Squared
|
|
|
593
603
|
return image(:push, opts, id: latest, registry: registry)
|
|
594
604
|
else
|
|
595
605
|
if op.empty?
|
|
596
|
-
ps, status, no = filter_ps
|
|
606
|
+
ps, status, no = filter_ps(flag, from: from)
|
|
597
607
|
cmd << '--no-stream' if flag == :stats
|
|
598
608
|
list_image(flag, ps, no: no, hint: status, multiple: flag != :attach, from: from) do |img|
|
|
599
609
|
run(cmd.temp(img), from: from)
|
|
600
610
|
end
|
|
601
611
|
return
|
|
602
612
|
end
|
|
603
|
-
|
|
613
|
+
case flag
|
|
614
|
+
when :logs, :diff, :attach, :top
|
|
615
|
+
op.add_first(escape: true, strip: ':')
|
|
616
|
+
if flag == :top
|
|
617
|
+
op.append(delim: true)
|
|
618
|
+
else
|
|
619
|
+
op.clear
|
|
620
|
+
end
|
|
621
|
+
else
|
|
622
|
+
op.append(escape: true, strip: ':')
|
|
623
|
+
end
|
|
604
624
|
end
|
|
605
625
|
run(from: from)
|
|
606
626
|
end
|
|
607
627
|
|
|
608
628
|
def image(flag, opts = [], sync: true, id: nil, registry: nil, filter: nil)
|
|
609
629
|
cmd, opts = docker_session('image', flag, opts: opts)
|
|
610
|
-
|
|
611
|
-
list
|
|
612
|
-
|
|
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)
|
|
613
634
|
exception = exception?
|
|
614
635
|
banner = true
|
|
615
636
|
from = symjoin 'image', flag
|
|
@@ -626,11 +647,18 @@ module Squared
|
|
|
626
647
|
break
|
|
627
648
|
end
|
|
628
649
|
list_image(:run, filter: filter, from: from) do |val|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
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)
|
|
634
662
|
index += 1
|
|
635
663
|
end
|
|
636
664
|
return
|
|
@@ -656,7 +684,7 @@ module Squared
|
|
|
656
684
|
op << val
|
|
657
685
|
found = true
|
|
658
686
|
if flag == :tag
|
|
659
|
-
op << tagname(
|
|
687
|
+
op << tagname(project, op.first)
|
|
660
688
|
break
|
|
661
689
|
end
|
|
662
690
|
end
|
|
@@ -665,36 +693,36 @@ module Squared
|
|
|
665
693
|
if !id
|
|
666
694
|
id = tagmain
|
|
667
695
|
elsif !op.arg?('a', 'all-tags') && !id.include?(':')
|
|
668
|
-
id =
|
|
696
|
+
id = tagname project, id
|
|
669
697
|
end
|
|
670
698
|
unless registry
|
|
671
699
|
registry = op.shift
|
|
672
|
-
registry ||= option('registry') ||
|
|
700
|
+
registry ||= option('registry') || self.registry unless id.include?('/')
|
|
673
701
|
end
|
|
674
702
|
cmd << shell_quote(tagjoin(registry, id))
|
|
675
703
|
when :push
|
|
676
704
|
id ||= option('tag', ignore: false) || op.shift || tagmain
|
|
677
|
-
registry ||= option('registry') || op.shift ||
|
|
705
|
+
registry ||= option('registry') || op.shift || self.registry
|
|
678
706
|
emptyargs op, flag
|
|
679
707
|
raise ArgumentError, message('username/registry not specified', hint: flag) unless registry
|
|
680
708
|
|
|
681
709
|
uri = shell_quote tagjoin(registry, id)
|
|
682
710
|
op << uri
|
|
683
|
-
img = docker_output 'image
|
|
711
|
+
img = docker_output 'image tag', id, uri
|
|
684
712
|
return unless confirm_command(img.to_s, cmd.to_s, target: id, as: registry, title: from)
|
|
685
713
|
|
|
686
714
|
@session = img
|
|
687
715
|
sync = false
|
|
688
|
-
exception
|
|
716
|
+
exception = true
|
|
689
717
|
banner = false
|
|
690
718
|
when :inspect, :history
|
|
691
719
|
raise ArgumentError, message('missing image', hint: flag) if op.empty?
|
|
692
720
|
|
|
693
721
|
if flag == :history
|
|
694
|
-
op.add_first(escape: true, strip:
|
|
722
|
+
op.add_first(escape: true, strip: ':')
|
|
695
723
|
.clear
|
|
696
724
|
else
|
|
697
|
-
op.append(escape: true, strip:
|
|
725
|
+
op.append(escape: true, strip: ':')
|
|
698
726
|
end
|
|
699
727
|
end
|
|
700
728
|
success?(run(sync: sync, exception: exception, banner: banner, from: from), flag == :tag || flag == :save)
|
|
@@ -702,7 +730,7 @@ module Squared
|
|
|
702
730
|
|
|
703
731
|
def network(flag, opts = [], target: nil)
|
|
704
732
|
cmd, opts = docker_session('network', flag, opts: opts)
|
|
705
|
-
op = OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd,
|
|
733
|
+
op = OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, **dockerinit)
|
|
706
734
|
.clear
|
|
707
735
|
from = symjoin 'network', flag
|
|
708
736
|
if flag == :create
|
|
@@ -753,7 +781,7 @@ module Squared
|
|
|
753
781
|
|
|
754
782
|
def read_composefile(*keys, target: nil)
|
|
755
783
|
require 'yaml'
|
|
756
|
-
target = ENV['COMPOSE_FILE']&.split(
|
|
784
|
+
target = ENV['COMPOSE_FILE']&.split(windows? ? ';' : ':') unless target && !target.empty?
|
|
757
785
|
Array(target || dockerfile).each do |val|
|
|
758
786
|
doc = YAML.load_file(basepath(val))
|
|
759
787
|
if keys.empty?
|
|
@@ -770,7 +798,7 @@ module Squared
|
|
|
770
798
|
opts = OptionPartition.union(Array(opts), @client) if @client
|
|
771
799
|
return session('docker', *cmd) unless opts
|
|
772
800
|
|
|
773
|
-
op = OptionPartition.new(opts, OPT_DOCKER[:common],
|
|
801
|
+
op = OptionPartition.new(opts, OPT_DOCKER[:common], **dockerinit)
|
|
774
802
|
[session('docker', *op.to_a, *cmd), op.extras]
|
|
775
803
|
end
|
|
776
804
|
|
|
@@ -778,12 +806,12 @@ module Squared
|
|
|
778
806
|
session('docker', *cmd, main: false, options: false, **kwargs)
|
|
779
807
|
end
|
|
780
808
|
|
|
781
|
-
def append_command(flag,
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
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
|
|
787
815
|
case flag
|
|
788
816
|
when :run
|
|
789
817
|
unless session_arg?('name', target: target)
|
|
@@ -792,8 +820,22 @@ module Squared
|
|
|
792
820
|
when :exec
|
|
793
821
|
raise ArgumentError, message('nothing to execute', hint: flag) if list.empty?
|
|
794
822
|
end
|
|
795
|
-
target <<
|
|
796
|
-
|
|
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
|
|
797
839
|
end
|
|
798
840
|
|
|
799
841
|
def append_file(type, target: @session, index: 2, force: false)
|
|
@@ -825,13 +867,13 @@ module Squared
|
|
|
825
867
|
else
|
|
826
868
|
Array(val)
|
|
827
869
|
end.each do |s|
|
|
828
|
-
s =
|
|
870
|
+
s = tagname s, ver if ver && (!s.include?(':') || s.delete_suffix!(':latest'))
|
|
829
871
|
target << basic_option('tag', tagname(s))
|
|
830
872
|
end
|
|
831
873
|
target
|
|
832
874
|
end
|
|
833
875
|
|
|
834
|
-
def filter_ps(flag,
|
|
876
|
+
def filter_ps(flag, meth = nil, from: meth || :'container:ps')
|
|
835
877
|
no = false
|
|
836
878
|
status = case flag.to_sym
|
|
837
879
|
when :start
|
|
@@ -865,7 +907,7 @@ module Squared
|
|
|
865
907
|
pwd_set(from: from) do
|
|
866
908
|
index = 1
|
|
867
909
|
all = option('all', prefix: 'docker')
|
|
868
|
-
y = from
|
|
910
|
+
y = from.to_s.end_with?(':rm') && option('y', prefix: 'docker')
|
|
869
911
|
filter = env('DOCKER_FILTER', filter).to_s
|
|
870
912
|
pat = if OptionPartition.pattern?(filter)
|
|
871
913
|
Regexp.new(filter)
|
|
@@ -901,17 +943,17 @@ module Squared
|
|
|
901
943
|
puts unless index == 1
|
|
902
944
|
puts (h + sub_style(aa, theme[:subject])).subhint("created #{e} ago")
|
|
903
945
|
cols = %w[Tag Status Ports]
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
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(', ')}" }
|
|
915
957
|
w = 9 + flag.to_s.size + 4 + ee.size
|
|
916
958
|
puts g + sub_style(ARG[:BORDER][6] + (ARG[:BORDER][1] * w), theme[:inline])
|
|
917
959
|
index += 1
|
|
@@ -994,7 +1036,7 @@ module Squared
|
|
|
994
1036
|
cmd = docker_output(ctx, *action)
|
|
995
1037
|
case flag
|
|
996
1038
|
when :tag
|
|
997
|
-
args = tagjoin
|
|
1039
|
+
args = tagjoin registry, tag
|
|
998
1040
|
when :save
|
|
999
1041
|
opts = opts.sub_ext('.tar')
|
|
1000
1042
|
cmd << quote_option('output', File.expand_path(opts))
|
|
@@ -1006,8 +1048,7 @@ module Squared
|
|
|
1006
1048
|
cmd << opts << '--'
|
|
1007
1049
|
end
|
|
1008
1050
|
cmd.merge(Array(out).map { |val| val.split(/\s+/, 2).first })
|
|
1009
|
-
cmd << args
|
|
1010
|
-
success?(run(cmd), ctx.start_with?('network', 'tag', 'save'))
|
|
1051
|
+
success?(run(cmd << args, { 'NO_COLOR' => 'true' }), ctx.start_with?('network', 'tag', 'save'))
|
|
1011
1052
|
end
|
|
1012
1053
|
|
|
1013
1054
|
def filetype(val = dockerfile)
|
|
@@ -1034,11 +1075,20 @@ module Squared
|
|
|
1034
1075
|
args.map { |val| val.chomp(char) }.join(char) unless args.empty?
|
|
1035
1076
|
end
|
|
1036
1077
|
|
|
1037
|
-
def tagname(val)
|
|
1038
|
-
val = val.
|
|
1078
|
+
def tagname(*val, max: 128)
|
|
1079
|
+
val = val.compact
|
|
1080
|
+
.join(':')
|
|
1081
|
+
.split(':')
|
|
1082
|
+
.map { |s| charname(s.sub(/^\W+/, '')) }
|
|
1039
1083
|
ret = val.join(':')
|
|
1040
|
-
ret
|
|
1041
|
-
|
|
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]
|
|
1042
1092
|
end
|
|
1043
1093
|
|
|
1044
1094
|
def dnsname(val)
|
|
@@ -1053,6 +1103,10 @@ module Squared
|
|
|
1053
1103
|
tag.is_a?(Array) ? tag.first : tag
|
|
1054
1104
|
end
|
|
1055
1105
|
|
|
1106
|
+
def dockerinit
|
|
1107
|
+
{ project: self, strict: strict?, explicit: '=', bool: %w[true false 1 0] }
|
|
1108
|
+
end
|
|
1109
|
+
|
|
1056
1110
|
def emptyargs(list, hint = nil)
|
|
1057
1111
|
raise ArgumentError, message('unrecognized args', list.join(', '), hint: hint) unless list.empty?
|
|
1058
1112
|
end
|