squared 0.5.25 → 0.6.0
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 +89 -274
- data/README.md +104 -72
- data/lib/squared/common/base.rb +1 -22
- data/lib/squared/common/format.rb +40 -38
- data/lib/squared/common/prompt.rb +58 -40
- data/lib/squared/common/shell.rb +71 -63
- data/lib/squared/common/system.rb +70 -38
- data/lib/squared/common/utils.rb +30 -15
- data/lib/squared/config.rb +27 -34
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +87 -113
- data/lib/squared/workspace/project/base.rb +548 -420
- data/lib/squared/workspace/project/docker.rb +410 -296
- data/lib/squared/workspace/project/git.rb +375 -371
- data/lib/squared/workspace/project/node.rb +501 -284
- data/lib/squared/workspace/project/python.rb +375 -255
- data/lib/squared/workspace/project/ruby.rb +697 -397
- data/lib/squared/workspace/project/support/class.rb +210 -213
- data/lib/squared/workspace/repo.rb +47 -44
- data/lib/squared/workspace/series.rb +13 -21
- data/lib/squared/workspace/support/base.rb +3 -24
- data/lib/squared/workspace/support/variables.rb +48 -0
- data/lib/squared/workspace/support.rb +1 -1
- data/lib/squared/workspace.rb +4 -6
- metadata +3 -3
- data/lib/squared/workspace/support/data.rb +0 -11
|
@@ -13,17 +13,18 @@ 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=
|
|
16
|
+
cgroup-parent=b iidfile=p label=q a-file=p network=b no-cache-filter=b o|output=q platform=b
|
|
17
17
|
q|quiet secret=qq shm-size=b ssh=qq t|tag=b target=b ulimit=q].freeze,
|
|
18
18
|
bake: %w[print list=q set=q].freeze,
|
|
19
19
|
shared: %w[check load no-cache pull push allow=q call=b? f|file=p metadata-file=p progress=b provenance=q
|
|
20
20
|
sbom=q].freeze
|
|
21
21
|
}.freeze,
|
|
22
22
|
compose: {
|
|
23
|
-
common: %w[all-resources compatibility dry-run
|
|
23
|
+
common: %w[all-resources ansi|b compatibility dry-run env-file=p f|file=p parallel=n profile=b progress=b
|
|
24
24
|
project-directory=p p|project-name=e].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
|
+
create: %w[build force-recreate no-build no-recreate quiet-pull remove-orphans y|yes pull=b scale=i].freeze,
|
|
27
28
|
exec: %w[d|detach privileged e|env=qq index=i T|no-TTY=b? user=e w|workdir=q].freeze,
|
|
28
29
|
run: %w[build d|detach no-deps q|quiet quiet-build quiet-pull remove-orphans rm P|service-ports use-aliases
|
|
29
30
|
cap-add=b cap-drop=b entrypoint=q e|env=qq env-from-file=p i|interactive=b? l|label=q name=b
|
|
@@ -41,14 +42,14 @@ module Squared
|
|
|
41
42
|
device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q
|
|
42
43
|
disable-content-trust=b? dns=q dns-option=q dns-search=q domainname=b entrypoint=q e|env=qq
|
|
43
44
|
env-file=p expose=q gpus=q group-add=b health-cmd=q health-interval=b health-retries=i
|
|
44
|
-
health-start-interval=q health-start-period=q health-timeout=q
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
memory-
|
|
48
|
-
|
|
49
|
-
stop-
|
|
50
|
-
|
|
51
|
-
run: %w[d|detach detach-keys=q sig-proxy=b?].freeze,
|
|
45
|
+
health-start-interval=q health-start-period=q health-timeout=q io-maxbandwidth=b io-maxiops=b
|
|
46
|
+
ip=b ip6=q ipc=b isolation=b kernel-memory=b l|label=q label-file=q link=b link-local-ip=q
|
|
47
|
+
log-driver=b log-opt=q mac-address=q m|memory=b memory-reservation=b memory-swap=n
|
|
48
|
+
memory-swappiness=n mount=qq name=b network=b network-alias=b oom-score-adj=b pid=b pids-limit=n
|
|
49
|
+
platform=b p|publish=q pull=b restart=b runtime=b security-opt=q shm-size=b stop-signal=b
|
|
50
|
+
stop-timeout=i storage-opt=q sysctl=q tmpfs=q ulimit=q u|user=b userns=b uts=b v|volume=q
|
|
51
|
+
volume-driver=b volumes-from=b w|workdir=q].freeze,
|
|
52
|
+
run: %w[d|detach detach-keys=q hostname=q sig-proxy=b?].freeze,
|
|
52
53
|
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
54
|
cpuset-cpus=b cpuset-mems=b m|memory=b memory-reservation=b memory-swap=b pids-limit=n
|
|
54
55
|
restart=q].freeze,
|
|
@@ -57,16 +58,16 @@ module Squared
|
|
|
57
58
|
commit: %w[a|author=q c|change=q m|message=q pause=b?].freeze,
|
|
58
59
|
inspect: %w[s|size f|format=q type=b].freeze,
|
|
59
60
|
start: %w[a|attach i|interactive detach-keys=q].freeze,
|
|
60
|
-
stop: %w[s|signal=b t|
|
|
61
|
-
restart: %w[s|signal=b t|
|
|
61
|
+
stop: %w[s|signal=b t|timeout=i].freeze,
|
|
62
|
+
restart: %w[s|signal=b t|timeout=i].freeze,
|
|
62
63
|
kill: %w[s|signal=b].freeze,
|
|
63
64
|
stats: %w[a|all no-stream no-trunc format|q].freeze
|
|
64
65
|
}.freeze,
|
|
65
66
|
image: {
|
|
66
|
-
|
|
67
|
-
push: %w[a|all-tags disable-content-trust=b? platform=
|
|
68
|
-
rm: %w[f|force no-prune platform=
|
|
69
|
-
save: %w[o|output=p platform=
|
|
67
|
+
ls: %w[a|all digests no-trunc q|quiet tree f|filter=q format=q].freeze,
|
|
68
|
+
push: %w[a|all-tags disable-content-trust=b? platform=b q|quiet].freeze,
|
|
69
|
+
rm: %w[f|force no-prune platform=b].freeze,
|
|
70
|
+
save: %w[o|output=p platform=b].freeze
|
|
70
71
|
}.freeze,
|
|
71
72
|
network: {
|
|
72
73
|
connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=q link=b link-local-ip=q].freeze,
|
|
@@ -80,6 +81,15 @@ module Squared
|
|
|
80
81
|
volume: %w[volume-subpath volume-nocopy volume-opt].freeze,
|
|
81
82
|
tmpfs: %w[tmpfs-size tmpfs-mode].freeze,
|
|
82
83
|
image: %w[image-path].freeze
|
|
84
|
+
}.freeze,
|
|
85
|
+
ls: {
|
|
86
|
+
compose: %w[Name Image Command Service RunningFor Status Ports CreatedAt ExitCode Health ID Labels
|
|
87
|
+
LocalVolumes Mounts Names Networks Project Publishers Size State].freeze,
|
|
88
|
+
container: %w[ID Image Command RunningFor Status Ports Names CreatedAt Labels LocalVolumes Mounts Networks
|
|
89
|
+
Platform Size State].freeze,
|
|
90
|
+
image: %w[Repository Tag ID Containers CreatedSince Size CreatedAt Digest SharedSize UniqueSize
|
|
91
|
+
VirtualSize].freeze,
|
|
92
|
+
network: %w[ID Name Driver Scope CreatedAt IPv4 IPv6 Internal Labels].freeze
|
|
83
93
|
}.freeze
|
|
84
94
|
}.freeze
|
|
85
95
|
private_constant :COMPOSEFILE, :BAKEFILE, :OPT_DOCKER, :VAL_DOCKER
|
|
@@ -98,12 +108,13 @@ module Squared
|
|
|
98
108
|
|
|
99
109
|
subtasks({
|
|
100
110
|
'build' => %i[tag context].freeze,
|
|
101
|
-
'compose' => %i[build run exec up down].freeze,
|
|
111
|
+
'compose' => %i[build create run exec up down service].freeze,
|
|
102
112
|
'bake' => %i[build check].freeze,
|
|
103
|
-
'image' => %i[
|
|
113
|
+
'image' => %i[ls rm push tag save].freeze,
|
|
104
114
|
'container' => %i[run create exec update commit inspect diff start stop restart pause unpause top stats kill
|
|
105
115
|
rm].freeze,
|
|
106
|
-
'network' => %i[connect disconnect].freeze
|
|
116
|
+
'network' => %i[connect disconnect].freeze,
|
|
117
|
+
'ls' => nil
|
|
107
118
|
})
|
|
108
119
|
|
|
109
120
|
attr_reader :context
|
|
@@ -136,114 +147,168 @@ module Squared
|
|
|
136
147
|
Docker.subtasks do |action, flags|
|
|
137
148
|
next if task_pass?(action)
|
|
138
149
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
150
|
+
if flags.nil?
|
|
151
|
+
case action
|
|
152
|
+
when 'ls'
|
|
153
|
+
format_desc(action, nil, VAL_DOCKER[:ls].keys, after: 'a/ll?,s/tandard?,range*', arg: nil)
|
|
154
|
+
task action, [:command] do |_, args|
|
|
155
|
+
command = param_guard(action, 'command', args: args, key: :command)
|
|
156
|
+
args = args.extras
|
|
157
|
+
a = args.delete('a') || args.delete('all')
|
|
158
|
+
ls = case command
|
|
159
|
+
when 'network'
|
|
160
|
+
a = nil
|
|
161
|
+
'ls'
|
|
162
|
+
when 'image', 'container'
|
|
163
|
+
'ls'
|
|
164
|
+
when 'compose'
|
|
165
|
+
'ps'
|
|
166
|
+
else
|
|
167
|
+
raise_error ArgumentError, 'unrecognized command', hint: command
|
|
168
|
+
end
|
|
169
|
+
data = VAL_DOCKER[:ls][command.to_sym]
|
|
170
|
+
if args.delete('s') || args.delete('standard')
|
|
171
|
+
cols = data.first(data.index('CreatedAt'))
|
|
172
|
+
else
|
|
173
|
+
cols = []
|
|
174
|
+
args.each do |val|
|
|
175
|
+
if val =~ /^(\d+)$/
|
|
176
|
+
cols << data[$1.to_i.pred]
|
|
177
|
+
elsif val =~ /^(\d+)(-|\.{2,3})(\d+)$/
|
|
178
|
+
j = $1.to_i.pred
|
|
179
|
+
k = $3.to_i - ($2 == '..' ? 2 : 1)
|
|
180
|
+
cols.concat(data[j..k]) if k > j
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
if cols.empty?
|
|
184
|
+
cols = choice_index('Select a column', data, multiple: true, force: true, attempts: 1)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
cmd = docker_output(command, ls, a && '-a')
|
|
188
|
+
cmd << quote_option('format', "table #{cols.map! { |val| "{{.#{val}}}" }.join("\t")}")
|
|
189
|
+
run(cmd, banner: false, from: :ls)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
else
|
|
193
|
+
namespace action do
|
|
194
|
+
flags.each do |flag|
|
|
195
|
+
case action
|
|
196
|
+
when 'build'
|
|
145
197
|
format_desc(action, flag, 'opts*', before: flag == :tag ? 'name' : 'dir')
|
|
146
198
|
task flag, [flag] do |_, args|
|
|
147
199
|
param = param_guard(action, flag, args: args, key: flag)
|
|
148
200
|
buildx(:build, args.extras, "#{flag}": param)
|
|
149
201
|
end
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
202
|
+
when 'bake'
|
|
203
|
+
break unless bake?
|
|
204
|
+
|
|
205
|
+
case flag
|
|
206
|
+
when :build
|
|
207
|
+
format_desc action, flag, 'opts*,target*,context?|:'
|
|
208
|
+
task flag do |_, args|
|
|
209
|
+
args = args.to_a
|
|
210
|
+
if args.first == ':'
|
|
211
|
+
choice_command :bake
|
|
212
|
+
else
|
|
213
|
+
buildx :bake, args
|
|
214
|
+
end
|
|
163
215
|
end
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
buildx :bake, ['allow=fs.read=*', 'call=check', target]
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
when 'compose'
|
|
173
|
-
break unless compose?
|
|
174
|
-
|
|
175
|
-
case flag
|
|
176
|
-
when :build, :up, :down
|
|
177
|
-
format_desc action, flag, 'opts*,service*|:'
|
|
178
|
-
task flag do |_, args|
|
|
179
|
-
compose! flag, args.to_a
|
|
180
|
-
end
|
|
181
|
-
when :exec, :run
|
|
182
|
-
format_desc action, flag, "service|:,command#{flag == :exec ? '' : '?'}|::,args*,opts*"
|
|
183
|
-
task flag, [:service] do |_, args|
|
|
184
|
-
service = param_guard(action, flag, args: args, key: :service)
|
|
185
|
-
compose!(flag, args.extras, service: service)
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
when 'container'
|
|
189
|
-
case flag
|
|
190
|
-
when :exec, :commit
|
|
191
|
-
format_desc(action, flag, flag == :exec ? 'id/name,opts*,args+|:' : 'id/name,tag?,opts*')
|
|
192
|
-
task flag, [:id] do |_, args|
|
|
193
|
-
if flag == :exec && !args.id
|
|
194
|
-
choice_command flag
|
|
195
|
-
else
|
|
196
|
-
id = param_guard(action, flag, args: args, key: :id)
|
|
197
|
-
container(flag, args.extras, id: id)
|
|
216
|
+
when :check
|
|
217
|
+
format_desc action, flag, 'target'
|
|
218
|
+
task flag, [:target] do |_, args|
|
|
219
|
+
target = param_guard(action, flag, args: args, key: :target)
|
|
220
|
+
buildx :bake, ['allow=fs.read=*', 'call=check', target]
|
|
198
221
|
end
|
|
199
222
|
end
|
|
200
|
-
when
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
223
|
+
when 'compose'
|
|
224
|
+
break unless compose?
|
|
225
|
+
|
|
226
|
+
case flag
|
|
227
|
+
when :exec, :run
|
|
228
|
+
format_desc action, flag, "service|:,command#{flag == :exec ? '' : '?'}|::,args*,opts*"
|
|
229
|
+
task flag, [:service] do |_, args|
|
|
230
|
+
service = param_guard(action, flag, args: args, key: :service)
|
|
231
|
+
compose!(flag, args.extras, service: service)
|
|
232
|
+
end
|
|
233
|
+
when :service
|
|
234
|
+
cmds = %w[down kill pause restart rm start stop top unpause watch].freeze
|
|
235
|
+
format_desc(action, flag, cmds, arg: nil, after: 'name+|:')
|
|
236
|
+
task flag, [:command] do |_, args|
|
|
237
|
+
command = param_guard(action, flag, args: args, key: :command)
|
|
238
|
+
raise_error ArgumentError, 'unrecognized command', hint: command unless cmds.include?(command)
|
|
239
|
+
service = args.extras
|
|
240
|
+
if service.first == ':'
|
|
241
|
+
choice_command flag, command
|
|
242
|
+
else
|
|
243
|
+
compose!(flag, [command], service: service.empty? || service)
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
else
|
|
247
|
+
format_desc action, flag, 'opts*,service*|:'
|
|
248
|
+
task flag do |_, args|
|
|
249
|
+
compose!(flag, args.to_a, multiple: true)
|
|
207
250
|
end
|
|
208
251
|
end
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
252
|
+
when 'container'
|
|
253
|
+
case flag
|
|
254
|
+
when :exec, :commit
|
|
255
|
+
format_desc(action, flag, flag == :exec ? 'id/name,opts*,args+|:' : 'id/name,tag?,opts*')
|
|
256
|
+
task flag, [:id] do |_, args|
|
|
257
|
+
if flag == :exec && !args.id
|
|
258
|
+
choice_command flag
|
|
259
|
+
else
|
|
260
|
+
id = param_guard(action, flag, args: args, key: :id)
|
|
261
|
+
container(flag, args.extras, id: id)
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
when :run, :create
|
|
265
|
+
format_desc action, flag, 'image,opts*,args*|:'
|
|
266
|
+
task flag, [:image] do |_, args|
|
|
267
|
+
if args.image
|
|
268
|
+
container(flag, args.extras, id: args.image)
|
|
269
|
+
else
|
|
270
|
+
choice_command flag
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
else
|
|
274
|
+
format_desc action, flag, "opts*,id/name#{flag == :update ? '+' : '*'}"
|
|
275
|
+
task flag do |_, args|
|
|
276
|
+
container flag, args.to_a
|
|
277
|
+
end
|
|
213
278
|
end
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
279
|
+
when 'image'
|
|
280
|
+
case flag
|
|
281
|
+
when :push
|
|
282
|
+
format_desc action, flag, 'tag,registry/username?,opts*'
|
|
283
|
+
task flag, [:tag] do |_, args|
|
|
284
|
+
id = param_guard(action, flag, args: args, key: :tag)
|
|
285
|
+
image(flag, args.extras, id: id)
|
|
286
|
+
end
|
|
287
|
+
else
|
|
288
|
+
format_desc(action, flag, case flag
|
|
289
|
+
when :rm, :save then 'id*,opts*'
|
|
290
|
+
when :tag then 'version?'
|
|
291
|
+
else 'opts*,args*'
|
|
292
|
+
end)
|
|
293
|
+
task flag do |_, args|
|
|
294
|
+
args = args.to_a
|
|
295
|
+
if !args.empty? || flag == :ls
|
|
296
|
+
image flag, args
|
|
297
|
+
else
|
|
298
|
+
choice_command flag
|
|
299
|
+
end
|
|
300
|
+
end
|
|
222
301
|
end
|
|
223
|
-
|
|
224
|
-
format_desc
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
end)
|
|
229
|
-
task flag do |_, args|
|
|
230
|
-
args = args.to_a
|
|
231
|
-
if args.empty? && flag != :list
|
|
232
|
-
choice_command flag
|
|
302
|
+
when 'network'
|
|
303
|
+
format_desc action, flag, 'target,opts*'
|
|
304
|
+
task flag, [:target] do |_, args|
|
|
305
|
+
if args.target
|
|
306
|
+
network(flag, args.extras, target: args.target)
|
|
233
307
|
else
|
|
234
|
-
|
|
308
|
+
choice_command flag
|
|
235
309
|
end
|
|
236
310
|
end
|
|
237
311
|
end
|
|
238
|
-
when 'network'
|
|
239
|
-
format_desc action, flag, 'target,opts*'
|
|
240
|
-
task flag, [:target] do |_, args|
|
|
241
|
-
if args.target
|
|
242
|
-
network(flag, args.extras, target: args.target)
|
|
243
|
-
else
|
|
244
|
-
choice_command flag
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
312
|
end
|
|
248
313
|
end
|
|
249
314
|
end
|
|
@@ -254,28 +319,29 @@ module Squared
|
|
|
254
319
|
def clean(*, sync: invoked_sync?('clean'), **)
|
|
255
320
|
if runnable?(@clean)
|
|
256
321
|
super
|
|
257
|
-
|
|
258
|
-
image :
|
|
322
|
+
else
|
|
323
|
+
image(:rm, sync: sync)
|
|
259
324
|
end
|
|
260
325
|
end
|
|
261
326
|
|
|
262
327
|
def compose(opts, flags = nil, script: false, args: nil, from: :run, **)
|
|
263
|
-
return opts
|
|
328
|
+
return opts unless script
|
|
264
329
|
|
|
330
|
+
ret = docker_session
|
|
265
331
|
if from == :run
|
|
266
332
|
if bake?(n = filetype)
|
|
267
|
-
ret
|
|
333
|
+
ret << 'buildx bake'
|
|
268
334
|
append_file n
|
|
269
335
|
from = :bake
|
|
270
336
|
elsif compose?(n)
|
|
271
|
-
ret
|
|
337
|
+
ret << 'compose build'
|
|
272
338
|
append_file n
|
|
273
339
|
from = :compose
|
|
274
340
|
else
|
|
275
|
-
ret
|
|
341
|
+
ret << 'build'
|
|
276
342
|
end
|
|
277
343
|
else
|
|
278
|
-
ret
|
|
344
|
+
ret << from
|
|
279
345
|
end
|
|
280
346
|
case opts
|
|
281
347
|
when String
|
|
@@ -285,10 +351,10 @@ module Squared
|
|
|
285
351
|
when Enumerable
|
|
286
352
|
ret.merge(opts.to_a)
|
|
287
353
|
end
|
|
288
|
-
[args, flags].each_with_index do |
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
354
|
+
[args, flags].each_with_index do |item, i|
|
|
355
|
+
next unless item && (data = append_any(item, target: []))
|
|
356
|
+
|
|
357
|
+
ret.merge(data.map! { |arg| i == 0 ? fill_option(arg) : quote_option('build-arg', arg) })
|
|
292
358
|
end
|
|
293
359
|
case from
|
|
294
360
|
when :run
|
|
@@ -311,8 +377,8 @@ module Squared
|
|
|
311
377
|
end
|
|
312
378
|
append_context
|
|
313
379
|
when :bake, :compose
|
|
314
|
-
option(from == :bake ? 'target' : 'service', ignore: false) do |
|
|
315
|
-
ret.merge(split_escape(
|
|
380
|
+
option(from == :bake ? 'target' : 'service', ignore: false) do |val|
|
|
381
|
+
ret.merge(split_escape(val).map! { |s| shell_quote(s) })
|
|
316
382
|
end
|
|
317
383
|
end
|
|
318
384
|
ret
|
|
@@ -320,57 +386,80 @@ module Squared
|
|
|
320
386
|
|
|
321
387
|
def buildx(flag, opts = [], tag: nil, context: nil)
|
|
322
388
|
cmd, opts = docker_session('buildx', opts: opts)
|
|
323
|
-
op =
|
|
324
|
-
|
|
325
|
-
|
|
389
|
+
op = OPT_DOCKER[:buildx].yield_self do |data|
|
|
390
|
+
OptionPartition.new(opts, data[:common], cmd, project: self)
|
|
391
|
+
.append(flag, quote: false)
|
|
392
|
+
.parse(data[flag == :bake ? :bake : :build] + data[:shared])
|
|
393
|
+
end
|
|
326
394
|
case flag
|
|
327
395
|
when :build, :context
|
|
328
396
|
append_tag(tag || option('tag', ignore: false) || self.tag)
|
|
329
397
|
append_context context
|
|
330
398
|
when :bake
|
|
331
|
-
op.
|
|
332
|
-
|
|
399
|
+
unless op.empty?
|
|
400
|
+
args = op.dup
|
|
401
|
+
op.reset
|
|
402
|
+
if Dir.exist?(args.last)
|
|
403
|
+
if projectpath?(val = args.pop)
|
|
404
|
+
context = val
|
|
405
|
+
else
|
|
406
|
+
op.push(val)
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
op.append(args, escape: true, strip: /^:/)
|
|
410
|
+
contextdir context if context
|
|
411
|
+
end
|
|
333
412
|
end
|
|
334
413
|
op.clear(pass: false)
|
|
335
414
|
run(from: :"buildx:#{flag}")
|
|
336
415
|
end
|
|
337
416
|
|
|
338
|
-
def compose!(flag, opts = [], service: nil)
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
read_composefile('services', target: op.values_of('f', 'file')) { |data| keys.merge(data.keys) }
|
|
351
|
-
service = unless keys.empty?
|
|
352
|
-
choice_index('Add services', keys, multiple: multiple, force: !multiple,
|
|
353
|
-
attempts: multiple ? 1 : 5)
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
if multiple
|
|
357
|
-
op.concat(service) if service
|
|
358
|
-
op.append(delim: true, escape: true, strip: /^:/)
|
|
417
|
+
def compose!(flag, opts = [], service: nil, multiple: false)
|
|
418
|
+
from = :"compose:#{flag}"
|
|
419
|
+
if flag == :service
|
|
420
|
+
command = opts.first
|
|
421
|
+
if service == true
|
|
422
|
+
cmd, status = filter_ps command, from
|
|
423
|
+
lines = IO.popen(cmd.temp('--services')).map(&:strip).reject(&:empty?)
|
|
424
|
+
return list_empty(hint: status) if lines.empty?
|
|
425
|
+
|
|
426
|
+
service = choice_index('Choose a service', lines, multiple: true, force: true, attempts: 1)
|
|
427
|
+
end
|
|
428
|
+
docker_session('compose', command, '--', *service)
|
|
359
429
|
else
|
|
360
|
-
|
|
361
|
-
|
|
430
|
+
cmd, opts = docker_session('compose', opts: opts)
|
|
431
|
+
op = OptionPartition.new(opts, OPT_DOCKER[:compose][:common], cmd, project: self)
|
|
432
|
+
append_file filetype unless op.arg?('f', 'file')
|
|
433
|
+
op << flag
|
|
434
|
+
op.parse(OPT_DOCKER[:compose].fetch(flag, []))
|
|
435
|
+
if op.remove(':') || service == ':'
|
|
436
|
+
keys = Set.new
|
|
437
|
+
read_composefile('services', target: op.values_of('f', 'file')) { |data| keys.merge(data.keys) }
|
|
438
|
+
service = unless keys.empty?
|
|
439
|
+
choice_index('Add services', keys, multiple: multiple, force: !multiple,
|
|
440
|
+
attempts: multiple ? 1 : 3)
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
if multiple
|
|
444
|
+
op.concat(service) if service
|
|
445
|
+
op.append(delim: true, escape: true, strip: /^:/)
|
|
446
|
+
else
|
|
447
|
+
raise_error ArgumentError, 'no service was selected', hint: flag unless service
|
|
448
|
+
append_command(flag, service, op.extras, prompt: '::')
|
|
449
|
+
end
|
|
362
450
|
end
|
|
363
|
-
run(from:
|
|
451
|
+
run(from: from)
|
|
364
452
|
end
|
|
365
|
-
alias compose_ compose!
|
|
366
453
|
|
|
367
454
|
def container(flag, opts = [], id: nil)
|
|
368
455
|
cmd, opts = docker_session('container', flag, opts: opts)
|
|
369
456
|
rc = flag == :run || flag == :create
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
457
|
+
op = OPT_DOCKER[:container].yield_self do |data|
|
|
458
|
+
list = data.fetch(flag, [])
|
|
459
|
+
list += data[:create] if flag == :run
|
|
460
|
+
list += data[:update] if rc
|
|
461
|
+
OptionPartition.new(opts, list, cmd, project: self, args: rc || flag == :exec)
|
|
462
|
+
end
|
|
374
463
|
from = :"container:#{flag}"
|
|
375
464
|
case flag
|
|
376
465
|
when :run, :create, :exec
|
|
@@ -387,12 +476,12 @@ module Squared
|
|
|
387
476
|
when 'bind', 'volume', 'image', 'tmpfs'
|
|
388
477
|
type = v
|
|
389
478
|
else
|
|
390
|
-
raise_error
|
|
479
|
+
raise_error TypeError, "unknown: #{v}", hint: flag
|
|
391
480
|
end
|
|
392
481
|
elsif all.include?(k)
|
|
393
482
|
unless type
|
|
394
|
-
VAL_DOCKER[:run].each_pair do |key,
|
|
395
|
-
next unless
|
|
483
|
+
VAL_DOCKER[:run].each_pair do |key, val|
|
|
484
|
+
next unless val.include?(k)
|
|
396
485
|
|
|
397
486
|
type = key.to_s unless key == :common
|
|
398
487
|
break
|
|
@@ -411,18 +500,18 @@ module Squared
|
|
|
411
500
|
log_message(Logger::INFO, 'unrecognized option', subject: from, hint: k)
|
|
412
501
|
end
|
|
413
502
|
end
|
|
414
|
-
raise_error
|
|
503
|
+
raise_error TypeError, 'none specified', hint: flag unless type
|
|
415
504
|
cmd << "--mount type=#{type},#{args.join(',')}"
|
|
416
505
|
end
|
|
417
506
|
end
|
|
418
507
|
append_command(flag, id || tagmain, op.extras)
|
|
419
|
-
when :update
|
|
420
|
-
raise_error
|
|
508
|
+
when :update
|
|
509
|
+
raise_error ArgumentError, 'missing container', hint: flag if op.empty?
|
|
421
510
|
op.append(escape: true, strip: /^:/)
|
|
422
511
|
when :commit
|
|
423
512
|
latest = op.shift || tagmain
|
|
424
513
|
cmd << id << latest
|
|
425
|
-
raise_error
|
|
514
|
+
raise_error ArgumentError, "unrecognized args: #{op.join(', ')}", hint: flag unless op.empty?
|
|
426
515
|
return unless confirm_command(cmd.to_s, title: from, target: id, as: latest)
|
|
427
516
|
|
|
428
517
|
registry = option('registry') || @registry
|
|
@@ -441,38 +530,12 @@ module Squared
|
|
|
441
530
|
return image(:push, opts, id: latest, registry: registry)
|
|
442
531
|
else
|
|
443
532
|
if op.empty?
|
|
444
|
-
status =
|
|
445
|
-
no
|
|
446
|
-
|
|
447
|
-
when :inspect, :diff
|
|
448
|
-
no = false
|
|
449
|
-
when :start
|
|
450
|
-
status = %w[created exited]
|
|
451
|
-
no = false
|
|
452
|
-
when :stop, :pause
|
|
453
|
-
status = %w[running restarting]
|
|
454
|
-
when :restart
|
|
455
|
-
status = %w[running paused exited]
|
|
456
|
-
when :unpause
|
|
457
|
-
status << 'paused'
|
|
458
|
-
no = false
|
|
459
|
-
when :top, :stats
|
|
460
|
-
status << 'running'
|
|
461
|
-
cmd << '--no-stream' if flag == :stats
|
|
462
|
-
no = false
|
|
463
|
-
when :kill
|
|
464
|
-
status = %w[running restarting paused]
|
|
465
|
-
when :rm
|
|
466
|
-
status = %w[created exited dead]
|
|
467
|
-
end
|
|
468
|
-
ps = docker_output('ps -a', *status.map { |s| quote_option('filter', "status=#{s}") })
|
|
469
|
-
list_image(flag, ps, no: no, hint: "status: #{status.join(', ')}", from: from) do |img|
|
|
470
|
-
run(cmd.temp(img), from: from)
|
|
471
|
-
end
|
|
533
|
+
ps, status, no = filter_ps flag, from
|
|
534
|
+
cmd << '--no-stream' if flag == :stats
|
|
535
|
+
list_image(flag, ps, no: no, hint: status, from: from) { |img| run(cmd.temp(img), from: from) }
|
|
472
536
|
return
|
|
473
|
-
else
|
|
474
|
-
op.append(escape: true, strip: /^:/)
|
|
475
537
|
end
|
|
538
|
+
op.append(escape: true, strip: /^:/)
|
|
476
539
|
end
|
|
477
540
|
run(from: from)
|
|
478
541
|
end
|
|
@@ -480,16 +543,21 @@ module Squared
|
|
|
480
543
|
def image(flag, opts = [], sync: true, id: nil, registry: nil)
|
|
481
544
|
cmd, opts = docker_session('image', flag, opts: opts)
|
|
482
545
|
op = OptionPartition.new(opts, OPT_DOCKER[:image].fetch(flag, []), cmd, project: self)
|
|
483
|
-
exception =
|
|
546
|
+
exception = self.exception
|
|
484
547
|
banner = true
|
|
485
548
|
from = :"image:#{flag}"
|
|
486
549
|
case flag
|
|
487
|
-
when :
|
|
550
|
+
when :ls
|
|
488
551
|
if opts.size == op.size
|
|
489
552
|
index = 0
|
|
490
553
|
name = nil
|
|
491
|
-
opts.reverse_each
|
|
492
|
-
|
|
554
|
+
opts.reverse_each do |opt|
|
|
555
|
+
if (name = opt[/^name=["']?(.+?)["']?$/, 1])
|
|
556
|
+
opts.delete(opt)
|
|
557
|
+
break
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
list_image(:run, from: from) do |val|
|
|
493
561
|
container(:run, if name
|
|
494
562
|
opts.dup << "name=#{index == 0 ? name : "#{name}-#{index}"}"
|
|
495
563
|
else
|
|
@@ -498,19 +566,12 @@ module Squared
|
|
|
498
566
|
index += 1
|
|
499
567
|
end
|
|
500
568
|
return
|
|
501
|
-
else
|
|
502
|
-
op.clear
|
|
503
569
|
end
|
|
570
|
+
op.clear
|
|
504
571
|
when :rm
|
|
505
|
-
|
|
506
|
-
op << id
|
|
507
|
-
if option('y')
|
|
508
|
-
exception = false
|
|
509
|
-
banner = false
|
|
510
|
-
end
|
|
511
|
-
else
|
|
572
|
+
unless id
|
|
512
573
|
if op.empty?
|
|
513
|
-
list_image(:rm,
|
|
574
|
+
list_image(:rm, from: from) do |val|
|
|
514
575
|
image(:rm, opts, sync: sync, id: val)
|
|
515
576
|
end
|
|
516
577
|
else
|
|
@@ -518,8 +579,13 @@ module Squared
|
|
|
518
579
|
end
|
|
519
580
|
return
|
|
520
581
|
end
|
|
582
|
+
op << id
|
|
583
|
+
if option('y')
|
|
584
|
+
exception = false
|
|
585
|
+
banner = false
|
|
586
|
+
end
|
|
521
587
|
when :tag, :save
|
|
522
|
-
list_image(flag,
|
|
588
|
+
list_image(flag, from: from) do |val|
|
|
523
589
|
op << val
|
|
524
590
|
if flag == :tag
|
|
525
591
|
op << tagname("#{project}:#{op.first}")
|
|
@@ -529,8 +595,14 @@ module Squared
|
|
|
529
595
|
when :push
|
|
530
596
|
id ||= option('tag', ignore: false) || tagmain
|
|
531
597
|
registry ||= op.shift || option('registry') || @registry
|
|
532
|
-
|
|
533
|
-
|
|
598
|
+
unless id && op.empty?
|
|
599
|
+
if id
|
|
600
|
+
raise_error ArgumentError, "unrecognized args: #{op.join(', ')}", hint: flag
|
|
601
|
+
else
|
|
602
|
+
raise_error 'no id/tag', hint: flag
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
raise_error ArgumentError, 'username/registry not specified', hint: flag unless registry
|
|
534
606
|
registry.chomp!('/')
|
|
535
607
|
uri = shell_quote "#{registry}/#{id}"
|
|
536
608
|
op << uri
|
|
@@ -542,17 +614,18 @@ module Squared
|
|
|
542
614
|
exception = true
|
|
543
615
|
banner = false
|
|
544
616
|
end
|
|
545
|
-
|
|
546
|
-
|
|
617
|
+
run(cmd, sync: sync, exception: exception, banner: banner, from: from).tap do |ret|
|
|
618
|
+
success?(ret, flag == :tag || flag == :save)
|
|
619
|
+
end
|
|
547
620
|
end
|
|
548
621
|
|
|
549
622
|
def network(flag, opts = [], target: nil)
|
|
550
623
|
cmd, opts = docker_session('network', flag, opts: opts)
|
|
551
|
-
|
|
552
|
-
|
|
624
|
+
OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, project: self)
|
|
625
|
+
.clear
|
|
553
626
|
from = :"network:#{flag}"
|
|
554
627
|
list_image(flag, docker_output('ps -a'), from: from) do |img|
|
|
555
|
-
|
|
628
|
+
success?(run(cmd.temp(target, img), from: from))
|
|
556
629
|
end
|
|
557
630
|
end
|
|
558
631
|
|
|
@@ -579,10 +652,10 @@ module Squared
|
|
|
579
652
|
def dockerfile(val = nil)
|
|
580
653
|
if val
|
|
581
654
|
@file = if val.is_a?(Array)
|
|
582
|
-
val = val.select { |file|
|
|
655
|
+
val = val.select { |file| exist?(file) }
|
|
583
656
|
val.size > 1 ? val : val.first
|
|
584
657
|
elsif val == true
|
|
585
|
-
DIR_DOCKER.find { |file|
|
|
658
|
+
DIR_DOCKER.find { |file| exist?(file) }
|
|
586
659
|
elsif val != 'Dockerfile'
|
|
587
660
|
val
|
|
588
661
|
end
|
|
@@ -611,8 +684,7 @@ module Squared
|
|
|
611
684
|
return session('docker', *cmd) unless opts
|
|
612
685
|
|
|
613
686
|
op = OptionPartition.new(opts, OPT_DOCKER[:common], project: self)
|
|
614
|
-
|
|
615
|
-
[ret, op.extras]
|
|
687
|
+
[session('docker', *op.to_a, *cmd), op.extras]
|
|
616
688
|
end
|
|
617
689
|
|
|
618
690
|
def docker_output(*cmd, **kwargs)
|
|
@@ -622,8 +694,8 @@ module Squared
|
|
|
622
694
|
def append_command(flag, val, list, target: @session, prompt: ':')
|
|
623
695
|
if list.delete(prompt)
|
|
624
696
|
list << readline('Enter command [args]', force: flag == :exec)
|
|
625
|
-
|
|
626
|
-
list << args
|
|
697
|
+
else
|
|
698
|
+
env('DOCKER_ARGS') { |args| list << args }
|
|
627
699
|
end
|
|
628
700
|
case flag
|
|
629
701
|
when :run
|
|
@@ -631,7 +703,7 @@ module Squared
|
|
|
631
703
|
target << basic_option('name', dnsname("#{name}_%s" % rand_s(6)))
|
|
632
704
|
end
|
|
633
705
|
when :exec
|
|
634
|
-
raise_error
|
|
706
|
+
raise_error ArgumentError, 'nothing to execute', hint: flag if list.empty?
|
|
635
707
|
end
|
|
636
708
|
target << val << list.shift
|
|
637
709
|
target << list.join(' && ') unless list.empty?
|
|
@@ -683,17 +755,45 @@ module Squared
|
|
|
683
755
|
end
|
|
684
756
|
end
|
|
685
757
|
|
|
686
|
-
def
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
758
|
+
def filter_ps(flag, from = :'container:ps')
|
|
759
|
+
no = false
|
|
760
|
+
status = case flag.to_sym
|
|
761
|
+
when :start
|
|
762
|
+
%w[created exited]
|
|
763
|
+
when :stop, :pause
|
|
764
|
+
no = true
|
|
765
|
+
%w[running restarting]
|
|
766
|
+
when :restart
|
|
767
|
+
no = true
|
|
768
|
+
%w[running paused exited]
|
|
769
|
+
when :unpause
|
|
770
|
+
%w[paused]
|
|
771
|
+
when :top, :stats, :watch
|
|
772
|
+
%w[running]
|
|
773
|
+
when :kill
|
|
774
|
+
no = true
|
|
775
|
+
%w[running paused restarting]
|
|
776
|
+
when :rm
|
|
777
|
+
no = true
|
|
778
|
+
%w[created exited dead]
|
|
779
|
+
else
|
|
780
|
+
[]
|
|
781
|
+
end
|
|
782
|
+
cmd = docker_output("#{from.to_s.split(':').first} ps -a",
|
|
783
|
+
*status.map { |s| quote_option('filter', "status=#{s}") })
|
|
784
|
+
[cmd, status, no]
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
def list_image(flag, cmd = docker_output('image ls -a'), hint: nil, from: nil, no: true)
|
|
788
|
+
pwd_set do
|
|
789
|
+
index = 1
|
|
690
790
|
all = option('all', prefix: 'docker')
|
|
691
791
|
y = from == :'image:rm' && option('y', prefix: 'docker')
|
|
692
792
|
pat = /\b(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':', 2).first})\b/
|
|
693
|
-
IO.popen(
|
|
793
|
+
IO.popen(cmd.temp('--format=json')).each do |line|
|
|
694
794
|
data = JSON.parse(line)
|
|
695
795
|
id = data['ID']
|
|
696
|
-
rt = [data['Repository'], data['Tag']].reject { |val| val == '<none>' }.join(':')
|
|
796
|
+
rt = [data['Repository'], data['Tag']].reject { |val| val.to_s.empty? || val == '<none>' }.join(':')
|
|
697
797
|
rt = nil if rt.empty?
|
|
698
798
|
aa = data['Names'] || (if rt && data['Repository']
|
|
699
799
|
dd = true
|
|
@@ -705,16 +805,16 @@ module Squared
|
|
|
705
805
|
next unless all || ee.match?(pat) || aa.match?(pat)
|
|
706
806
|
|
|
707
807
|
unless y
|
|
708
|
-
bb = index.
|
|
709
|
-
cc = bb.size
|
|
808
|
+
bb = index.to_s
|
|
809
|
+
cc = bb.size.succ
|
|
710
810
|
a = sub_style(ee, styles: theme[:inline])
|
|
711
|
-
b = "Execute #{sub_style(flag, styles: theme[:active])} on #{a
|
|
811
|
+
b = "Execute #{sub_style(flag, styles: theme[:active])} on #{a.subhint(ee == id ? nil : id)}"
|
|
712
812
|
e = time_format(time_since(data['CreatedAt']), pass: ['ms'])
|
|
713
813
|
f = sub_style(ARG[:BORDER][0], styles: theme[:inline])
|
|
714
|
-
g = ' ' *
|
|
814
|
+
g = ' ' * cc.succ
|
|
715
815
|
h = "#{sub_style(bb.rjust(cc), styles: theme[:current])} #{f} "
|
|
716
|
-
puts unless index ==
|
|
717
|
-
puts
|
|
816
|
+
puts unless index == 1
|
|
817
|
+
puts (h + sub_style(aa, styles: theme[:subject])).subhint("created #{e} ago")
|
|
718
818
|
cols = %w[Tag Status Ports]
|
|
719
819
|
cols << case flag
|
|
720
820
|
when :connect, :disconnect
|
|
@@ -729,89 +829,104 @@ module Squared
|
|
|
729
829
|
end
|
|
730
830
|
w = 9 + flag.to_s.size + 4 + ee.size
|
|
731
831
|
puts g + sub_style(ARG[:BORDER][6] + (ARG[:BORDER][1] * w), styles: theme[:inline])
|
|
732
|
-
found = true
|
|
733
832
|
index += 1
|
|
734
|
-
next unless confirm("#{h + b}?", no ? 'N' : 'Y'
|
|
833
|
+
next unless confirm("#{h + b}?", no ? 'N' : 'Y')
|
|
735
834
|
|
|
736
835
|
puts if printfirst?
|
|
737
836
|
end
|
|
738
837
|
yield id
|
|
739
838
|
end
|
|
740
|
-
|
|
839
|
+
list_empty(hint: hint || from) if index == 1 && !y
|
|
741
840
|
end
|
|
742
841
|
rescue StandardError => e
|
|
743
842
|
on_error e, from
|
|
744
843
|
end
|
|
745
844
|
|
|
845
|
+
def list_empty(subject: name, hint: nil, **kwargs)
|
|
846
|
+
hint = "status: #{hint.join(', ')}" if hint.is_a?(Array)
|
|
847
|
+
puts log_message(Logger::INFO, 'none detected', subject: subject, hint: hint, **kwargs)
|
|
848
|
+
end
|
|
849
|
+
|
|
746
850
|
def confirm_command(*args, title: nil, target: nil, as: nil)
|
|
747
851
|
return false unless title && target
|
|
748
852
|
|
|
749
853
|
puts unless printfirst?
|
|
750
854
|
t = title.to_s.split(':')
|
|
751
855
|
emphasize(args, title: message(t.first.upcase, *t.drop(1)), border: borderstyle, sub: [
|
|
752
|
-
|
|
753
|
-
|
|
856
|
+
opt_style(theme[:header], /\A(\w+(?: => \w+)+)(.*)\z/),
|
|
857
|
+
opt_style(theme[:caution], /\A(.+)\z/)
|
|
754
858
|
])
|
|
755
859
|
printsucc
|
|
756
860
|
a = t.last.capitalize
|
|
757
861
|
b = sub_style(target, styles: theme[:subject])
|
|
758
862
|
c = as && sub_style(as, styles: theme[:inline])
|
|
759
|
-
confirm
|
|
760
|
-
end
|
|
761
|
-
|
|
762
|
-
def choice_command(flag)
|
|
763
|
-
msg, cmd
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
863
|
+
confirm "#{a} #{b}#{c ? " as #{c}" : ''}?", 'N'
|
|
864
|
+
end
|
|
865
|
+
|
|
866
|
+
def choice_command(flag, *action)
|
|
867
|
+
msg, cmd = case flag
|
|
868
|
+
when :exec
|
|
869
|
+
['Choose a container', 'ps -a']
|
|
870
|
+
when :bake
|
|
871
|
+
['Choose a target', 'buildx bake --list=type=targets']
|
|
872
|
+
when :connect, :disconnect
|
|
873
|
+
['Choose a network', 'network ls']
|
|
874
|
+
when :service
|
|
875
|
+
['Choose a service',
|
|
876
|
+
'compose ps -a ' \
|
|
877
|
+
"--format='table {{.Service}}\t{{.Name}}\t{{.Image}}\t{{.Command}}\t{{.Status}}\t{{.Ports}}'"]
|
|
878
|
+
else
|
|
879
|
+
['Choose an image',
|
|
880
|
+
'images -a ' \
|
|
881
|
+
"--format='table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.CreatedSince}}\t{{.Size}}'"]
|
|
882
|
+
end
|
|
773
883
|
lines = `#{docker_output(cmd)}`.lines
|
|
774
884
|
header = lines.shift
|
|
775
885
|
if lines.empty?
|
|
776
|
-
puts log_message(Logger::INFO, 'none found', subject: name,
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
886
|
+
puts log_message(Logger::INFO, 'none found', subject: name,
|
|
887
|
+
hint: "docker #{cmd.split(' ', 3)[0...2].join(' ')}")
|
|
888
|
+
return
|
|
889
|
+
end
|
|
890
|
+
puts " # #{header}"
|
|
891
|
+
multiple = false
|
|
892
|
+
parse = ->(val) { val.split(/\s+/)[0] }
|
|
893
|
+
ctx = flag.to_s
|
|
894
|
+
case flag
|
|
895
|
+
when :run, :exec
|
|
896
|
+
values = [['Options', flag == :run], ['Arguments', flag == :exec]]
|
|
897
|
+
when :rm, :bake
|
|
898
|
+
values = ['Options']
|
|
899
|
+
multiple = true
|
|
900
|
+
ctx = flag == :rm ? 'image rm' : "buildx bake -f #{shell_quote(dockerfile)}"
|
|
901
|
+
when :save
|
|
902
|
+
values = [['Output', true], 'Platform']
|
|
903
|
+
multiple = true
|
|
904
|
+
when :service
|
|
905
|
+
values = []
|
|
906
|
+
multiple = true
|
|
907
|
+
ctx = 'compose'
|
|
908
|
+
when :connect, :disconnect
|
|
909
|
+
values = ['Options', ['Container', true]]
|
|
910
|
+
ctx = "network #{flag}"
|
|
911
|
+
end
|
|
912
|
+
out, opts, args = choice_index(msg, lines, multiple: multiple, values: values)
|
|
913
|
+
cmd = docker_output(ctx, *action)
|
|
914
|
+
case flag
|
|
915
|
+
when :tag
|
|
916
|
+
args = tagjoin @registry, tag
|
|
917
|
+
when :save
|
|
918
|
+
opts = "#{opts}.tar" unless opts.end_with?('.tar')
|
|
919
|
+
cmd << quote_option('output', File.expand_path(opts))
|
|
920
|
+
if args
|
|
921
|
+
cmd << basic_option('platform', args)
|
|
922
|
+
args = nil
|
|
810
923
|
end
|
|
811
|
-
|
|
812
|
-
cmd <<
|
|
813
|
-
print_success if success?(run(cmd), ctx.start_with?(/network|tag|save/))
|
|
924
|
+
else
|
|
925
|
+
cmd << opts << '--'
|
|
814
926
|
end
|
|
927
|
+
cmd.merge(Array(out).map! { |val| parse.call(val) })
|
|
928
|
+
cmd << args
|
|
929
|
+
success?(run(cmd), ctx.start_with?(/(?:network|tag|save)/))
|
|
815
930
|
end
|
|
816
931
|
|
|
817
932
|
def filetype(val = dockerfile)
|
|
@@ -840,10 +955,9 @@ module Squared
|
|
|
840
955
|
|
|
841
956
|
def tagname(val)
|
|
842
957
|
val = val.split(':').map! { |s| charname(s.sub(/^\W+/, '')) }
|
|
843
|
-
val.join(':')
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
end
|
|
958
|
+
ret = val.join(':')
|
|
959
|
+
ret = val.first if val.size > 1 && ret.size > 128
|
|
960
|
+
ret[0..127]
|
|
847
961
|
end
|
|
848
962
|
|
|
849
963
|
def dnsname(val)
|