squared 0.5.11 → 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 +127 -0
- data/README.md +76 -35
- data/lib/squared/common/base.rb +1 -22
- data/lib/squared/common/format.rb +33 -25
- data/lib/squared/common/prompt.rb +58 -36
- data/lib/squared/common/shell.rb +44 -11
- data/lib/squared/common/system.rb +69 -36
- data/lib/squared/common/utils.rb +29 -6
- data/lib/squared/config.rb +17 -21
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +87 -91
- data/lib/squared/workspace/project/base.rb +548 -378
- data/lib/squared/workspace/project/docker.rb +393 -290
- data/lib/squared/workspace/project/git.rb +328 -312
- data/lib/squared/workspace/project/node.rb +545 -280
- data/lib/squared/workspace/project/python.rb +329 -200
- data/lib/squared/workspace/project/ruby.rb +672 -343
- data/lib/squared/workspace/project/support/class.rb +166 -68
- data/lib/squared/workspace/repo.rb +39 -35
- data/lib/squared/workspace/series.rb +6 -6
- data/lib/squared/workspace/support/base.rb +3 -29
- data/lib/squared/workspace/support/variables.rb +48 -0
- data/lib/squared/workspace/support.rb +1 -1
- data/lib/squared/workspace.rb +1 -1
- metadata +4 -7
- data/lib/squared/workspace/support/data.rb +0 -11
|
@@ -13,21 +13,22 @@ 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
|
|
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
|
-
cap-add=b cap-drop=b q e|env=qq env-from-file=p i|interactive=b? l|label=q name=b
|
|
30
|
-
p|publish=
|
|
30
|
+
cap-add=b cap-drop=b entrypoint=q e|env=qq env-from-file=p i|interactive=b? l|label=q name=b
|
|
31
|
+
T|no-TTY=b? p|publish=q pull=b u|user=e v|volume=q w|workdir=q].freeze,
|
|
31
32
|
up: %w[abort-on-container-exit abort-on-container-failure always-recreate-deps attach-dependencies build
|
|
32
33
|
d|detach force-recreate menu no-build no-color no-deps no-log-prefix no-recreate no-start quiet-build
|
|
33
34
|
quiet-pull remove-orphans V|renew-anon-volumes timestamps wait w|watch y|yes attach=b
|
|
@@ -36,39 +37,40 @@ module Squared
|
|
|
36
37
|
}.freeze,
|
|
37
38
|
container: {
|
|
38
39
|
create: %w[init i|interactive no-healthcheck oom-kill-disable privileged P|publish-all q|quiet read-only
|
|
39
|
-
rm
|
|
40
|
-
|
|
41
|
-
device
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
rm t|tty use-api-socket add-host=q annotation=q a|attach=b blkio-weight=i blkio-weight-device=i
|
|
41
|
+
cap-add=b cap-drop=b cgroup-parent=b cgroupns=b cidfile=p device=q device-cgroup-rule=q
|
|
42
|
+
device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q
|
|
43
|
+
disable-content-trust=b? dns=q dns-option=q dns-search=q domainname=b entrypoint=q e|env=qq
|
|
44
|
+
env-file=p expose=q gpus=q group-add=b health-cmd=q health-interval=b health-retries=i
|
|
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,
|
|
51
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
|
|
52
54
|
cpuset-cpus=b cpuset-mems=b m|memory=b memory-reservation=b memory-swap=b pids-limit=n
|
|
53
55
|
restart=q].freeze,
|
|
54
56
|
exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p user=e
|
|
55
57
|
w|workdir=q].freeze,
|
|
56
58
|
commit: %w[a|author=q c|change=q m|message=q pause=b?].freeze,
|
|
57
|
-
inspect: %w[s|size f|format=q].freeze,
|
|
59
|
+
inspect: %w[s|size f|format=q type=b].freeze,
|
|
58
60
|
start: %w[a|attach i|interactive detach-keys=q].freeze,
|
|
59
|
-
stop: %w[s|signal=b t|
|
|
60
|
-
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,
|
|
61
63
|
kill: %w[s|signal=b].freeze,
|
|
62
64
|
stats: %w[a|all no-stream no-trunc format|q].freeze
|
|
63
65
|
}.freeze,
|
|
64
66
|
image: {
|
|
65
|
-
|
|
67
|
+
ls: %w[a|all digests no-trunc q|quiet tree f|filter=q format=q].freeze,
|
|
66
68
|
push: %w[a|all-tags disable-content-trust=b? platform=b q|quiet].freeze,
|
|
67
69
|
rm: %w[f|force no-prune platform=b].freeze,
|
|
68
70
|
save: %w[o|output=p platform=b].freeze
|
|
69
71
|
}.freeze,
|
|
70
72
|
network: {
|
|
71
|
-
connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=
|
|
73
|
+
connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=q link=b link-local-ip=q].freeze,
|
|
72
74
|
disconnect: %w[f|force].freeze
|
|
73
75
|
}.freeze
|
|
74
76
|
}.freeze
|
|
@@ -79,6 +81,15 @@ module Squared
|
|
|
79
81
|
volume: %w[volume-subpath volume-nocopy volume-opt].freeze,
|
|
80
82
|
tmpfs: %w[tmpfs-size tmpfs-mode].freeze,
|
|
81
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
|
|
82
93
|
}.freeze
|
|
83
94
|
}.freeze
|
|
84
95
|
private_constant :COMPOSEFILE, :BAKEFILE, :OPT_DOCKER, :VAL_DOCKER
|
|
@@ -97,12 +108,13 @@ module Squared
|
|
|
97
108
|
|
|
98
109
|
subtasks({
|
|
99
110
|
'build' => %i[tag context].freeze,
|
|
100
|
-
'compose' => %i[build run exec up down].freeze,
|
|
111
|
+
'compose' => %i[build create run exec up down service].freeze,
|
|
101
112
|
'bake' => %i[build check].freeze,
|
|
102
|
-
'image' => %i[
|
|
113
|
+
'image' => %i[ls rm push tag save].freeze,
|
|
103
114
|
'container' => %i[run create exec update commit inspect diff start stop restart pause unpause top stats kill
|
|
104
115
|
rm].freeze,
|
|
105
|
-
'network' => %i[connect disconnect].freeze
|
|
116
|
+
'network' => %i[connect disconnect].freeze,
|
|
117
|
+
'ls' => nil
|
|
106
118
|
})
|
|
107
119
|
|
|
108
120
|
attr_reader :context
|
|
@@ -135,114 +147,168 @@ module Squared
|
|
|
135
147
|
Docker.subtasks do |action, flags|
|
|
136
148
|
next if task_pass?(action)
|
|
137
149
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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'
|
|
144
197
|
format_desc(action, flag, 'opts*', before: flag == :tag ? 'name' : 'dir')
|
|
145
198
|
task flag, [flag] do |_, args|
|
|
146
199
|
param = param_guard(action, flag, args: args, key: flag)
|
|
147
200
|
buildx(:build, args.extras, "#{flag}": param)
|
|
148
201
|
end
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
|
162
215
|
end
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
buildx :bake, ['allow=fs.read=*', 'call=check', target]
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
when 'compose'
|
|
172
|
-
break unless compose?
|
|
173
|
-
|
|
174
|
-
case flag
|
|
175
|
-
when :build, :up, :down
|
|
176
|
-
format_desc action, flag, 'opts*,service*|:'
|
|
177
|
-
task flag do |_, args|
|
|
178
|
-
compose! flag, args.to_a
|
|
179
|
-
end
|
|
180
|
-
when :exec, :run
|
|
181
|
-
format_desc action, flag, "service|:,command#{flag == :exec ? '' : '?'}|::,args*,opts*"
|
|
182
|
-
task flag, [:service] do |_, args|
|
|
183
|
-
service = param_guard(action, flag, args: args, key: :service)
|
|
184
|
-
compose!(flag, args.extras, service: service)
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
when 'container'
|
|
188
|
-
case flag
|
|
189
|
-
when :exec, :commit
|
|
190
|
-
format_desc(action, flag, flag == :exec ? 'id/name,opts*,args+|:' : 'id/name,tag?,opts*')
|
|
191
|
-
task flag, [:id] do |_, args|
|
|
192
|
-
if flag == :exec && !args.id
|
|
193
|
-
choice_command flag
|
|
194
|
-
else
|
|
195
|
-
id = param_guard(action, flag, args: args, key: :id)
|
|
196
|
-
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]
|
|
197
221
|
end
|
|
198
222
|
end
|
|
199
|
-
when
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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)
|
|
206
250
|
end
|
|
207
251
|
end
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
|
212
278
|
end
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
|
221
301
|
end
|
|
222
|
-
|
|
223
|
-
format_desc
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
end)
|
|
228
|
-
task flag do |_, args|
|
|
229
|
-
args = args.to_a
|
|
230
|
-
if args.empty? && flag != :list
|
|
231
|
-
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)
|
|
232
307
|
else
|
|
233
|
-
|
|
308
|
+
choice_command flag
|
|
234
309
|
end
|
|
235
310
|
end
|
|
236
311
|
end
|
|
237
|
-
when 'network'
|
|
238
|
-
format_desc action, flag, 'target,opts*'
|
|
239
|
-
task flag, [:target] do |_, args|
|
|
240
|
-
if args.target
|
|
241
|
-
network(flag, args.extras, target: args.target)
|
|
242
|
-
else
|
|
243
|
-
choice_command flag
|
|
244
|
-
end
|
|
245
|
-
end
|
|
246
312
|
end
|
|
247
313
|
end
|
|
248
314
|
end
|
|
@@ -259,7 +325,7 @@ module Squared
|
|
|
259
325
|
end
|
|
260
326
|
|
|
261
327
|
def compose(opts, flags = nil, script: false, args: nil, from: :run, **)
|
|
262
|
-
return opts
|
|
328
|
+
return opts unless script
|
|
263
329
|
|
|
264
330
|
ret = docker_session
|
|
265
331
|
if from == :run
|
|
@@ -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,9 +386,11 @@ 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)
|
|
@@ -346,46 +414,56 @@ module Squared
|
|
|
346
414
|
run(from: :"buildx:#{flag}")
|
|
347
415
|
end
|
|
348
416
|
|
|
349
|
-
def compose!(flag, opts = [], service: nil)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
read_composefile('services', target: op.values_of('f', 'file')) { |data| keys.merge(data.keys) }
|
|
362
|
-
service = unless keys.empty?
|
|
363
|
-
choice_index('Add services', keys, multiple: multiple, force: !multiple,
|
|
364
|
-
attempts: multiple ? 1 : 5)
|
|
365
|
-
end
|
|
366
|
-
end
|
|
367
|
-
if multiple
|
|
368
|
-
op.concat(service) if service
|
|
369
|
-
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)
|
|
370
429
|
else
|
|
371
|
-
|
|
372
|
-
|
|
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
|
|
373
450
|
end
|
|
374
|
-
run(from:
|
|
451
|
+
run(from: from)
|
|
375
452
|
end
|
|
376
453
|
|
|
377
454
|
def container(flag, opts = [], id: nil)
|
|
378
455
|
cmd, opts = docker_session('container', flag, opts: opts)
|
|
379
456
|
rc = flag == :run || flag == :create
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
|
384
463
|
from = :"container:#{flag}"
|
|
385
464
|
case flag
|
|
386
465
|
when :run, :create, :exec
|
|
387
466
|
if rc && !op.arg?('mount')
|
|
388
|
-
run = VAL_DOCKER[:run]
|
|
389
467
|
all = collect_hash VAL_DOCKER[:run]
|
|
390
468
|
delim = Regexp.new(",\\s*(?=#{all.join('|')})")
|
|
391
469
|
Array(@mounts).each do |val|
|
|
@@ -398,11 +476,11 @@ module Squared
|
|
|
398
476
|
when 'bind', 'volume', 'image', 'tmpfs'
|
|
399
477
|
type = v
|
|
400
478
|
else
|
|
401
|
-
raise_error
|
|
479
|
+
raise_error TypeError, "unknown: #{v}", hint: flag
|
|
402
480
|
end
|
|
403
481
|
elsif all.include?(k)
|
|
404
482
|
unless type
|
|
405
|
-
run.each_pair do |key, val|
|
|
483
|
+
VAL_DOCKER[:run].each_pair do |key, val|
|
|
406
484
|
next unless val.include?(k)
|
|
407
485
|
|
|
408
486
|
type = key.to_s unless key == :common
|
|
@@ -422,18 +500,18 @@ module Squared
|
|
|
422
500
|
log_message(Logger::INFO, 'unrecognized option', subject: from, hint: k)
|
|
423
501
|
end
|
|
424
502
|
end
|
|
425
|
-
raise_error
|
|
503
|
+
raise_error TypeError, 'none specified', hint: flag unless type
|
|
426
504
|
cmd << "--mount type=#{type},#{args.join(',')}"
|
|
427
505
|
end
|
|
428
506
|
end
|
|
429
507
|
append_command(flag, id || tagmain, op.extras)
|
|
430
508
|
when :update
|
|
431
|
-
raise_error
|
|
509
|
+
raise_error ArgumentError, 'missing container', hint: flag if op.empty?
|
|
432
510
|
op.append(escape: true, strip: /^:/)
|
|
433
511
|
when :commit
|
|
434
512
|
latest = op.shift || tagmain
|
|
435
513
|
cmd << id << latest
|
|
436
|
-
raise_error
|
|
514
|
+
raise_error ArgumentError, "unrecognized args: #{op.join(', ')}", hint: flag unless op.empty?
|
|
437
515
|
return unless confirm_command(cmd.to_s, title: from, target: id, as: latest)
|
|
438
516
|
|
|
439
517
|
registry = option('registry') || @registry
|
|
@@ -452,38 +530,12 @@ module Squared
|
|
|
452
530
|
return image(:push, opts, id: latest, registry: registry)
|
|
453
531
|
else
|
|
454
532
|
if op.empty?
|
|
455
|
-
status =
|
|
456
|
-
no
|
|
457
|
-
|
|
458
|
-
when :inspect, :diff
|
|
459
|
-
no = false
|
|
460
|
-
when :start
|
|
461
|
-
status = %w[created exited]
|
|
462
|
-
no = false
|
|
463
|
-
when :stop, :pause
|
|
464
|
-
status = %w[running restarting]
|
|
465
|
-
when :restart
|
|
466
|
-
status = %w[running paused exited]
|
|
467
|
-
when :unpause
|
|
468
|
-
status << 'paused'
|
|
469
|
-
no = false
|
|
470
|
-
when :top, :stats
|
|
471
|
-
status << 'running'
|
|
472
|
-
cmd << '--no-stream' if flag == :stats
|
|
473
|
-
no = false
|
|
474
|
-
when :kill
|
|
475
|
-
status = %w[running restarting paused]
|
|
476
|
-
when :rm
|
|
477
|
-
status = %w[created exited dead]
|
|
478
|
-
end
|
|
479
|
-
ps = docker_output('ps -a', *status.map { |s| quote_option('filter', "status=#{s}") })
|
|
480
|
-
list_image(flag, ps, no: no, hint: "status: #{status.join(', ')}", from: from) do |img|
|
|
481
|
-
run(cmd.temp(img), from: from)
|
|
482
|
-
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) }
|
|
483
536
|
return
|
|
484
|
-
else
|
|
485
|
-
op.append(escape: true, strip: /^:/)
|
|
486
537
|
end
|
|
538
|
+
op.append(escape: true, strip: /^:/)
|
|
487
539
|
end
|
|
488
540
|
run(from: from)
|
|
489
541
|
end
|
|
@@ -491,16 +543,21 @@ module Squared
|
|
|
491
543
|
def image(flag, opts = [], sync: true, id: nil, registry: nil)
|
|
492
544
|
cmd, opts = docker_session('image', flag, opts: opts)
|
|
493
545
|
op = OptionPartition.new(opts, OPT_DOCKER[:image].fetch(flag, []), cmd, project: self)
|
|
494
|
-
exception =
|
|
546
|
+
exception = self.exception
|
|
495
547
|
banner = true
|
|
496
548
|
from = :"image:#{flag}"
|
|
497
549
|
case flag
|
|
498
|
-
when :
|
|
550
|
+
when :ls
|
|
499
551
|
if opts.size == op.size
|
|
500
552
|
index = 0
|
|
501
553
|
name = nil
|
|
502
|
-
opts.reverse_each
|
|
503
|
-
|
|
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|
|
|
504
561
|
container(:run, if name
|
|
505
562
|
opts.dup << "name=#{index == 0 ? name : "#{name}-#{index}"}"
|
|
506
563
|
else
|
|
@@ -509,19 +566,12 @@ module Squared
|
|
|
509
566
|
index += 1
|
|
510
567
|
end
|
|
511
568
|
return
|
|
512
|
-
else
|
|
513
|
-
op.clear
|
|
514
569
|
end
|
|
570
|
+
op.clear
|
|
515
571
|
when :rm
|
|
516
|
-
|
|
517
|
-
op << id
|
|
518
|
-
if option('y')
|
|
519
|
-
exception = false
|
|
520
|
-
banner = false
|
|
521
|
-
end
|
|
522
|
-
else
|
|
572
|
+
unless id
|
|
523
573
|
if op.empty?
|
|
524
|
-
list_image(:rm,
|
|
574
|
+
list_image(:rm, from: from) do |val|
|
|
525
575
|
image(:rm, opts, sync: sync, id: val)
|
|
526
576
|
end
|
|
527
577
|
else
|
|
@@ -529,8 +579,13 @@ module Squared
|
|
|
529
579
|
end
|
|
530
580
|
return
|
|
531
581
|
end
|
|
582
|
+
op << id
|
|
583
|
+
if option('y')
|
|
584
|
+
exception = false
|
|
585
|
+
banner = false
|
|
586
|
+
end
|
|
532
587
|
when :tag, :save
|
|
533
|
-
list_image(flag,
|
|
588
|
+
list_image(flag, from: from) do |val|
|
|
534
589
|
op << val
|
|
535
590
|
if flag == :tag
|
|
536
591
|
op << tagname("#{project}:#{op.first}")
|
|
@@ -540,8 +595,14 @@ module Squared
|
|
|
540
595
|
when :push
|
|
541
596
|
id ||= option('tag', ignore: false) || tagmain
|
|
542
597
|
registry ||= op.shift || option('registry') || @registry
|
|
543
|
-
|
|
544
|
-
|
|
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
|
|
545
606
|
registry.chomp!('/')
|
|
546
607
|
uri = shell_quote "#{registry}/#{id}"
|
|
547
608
|
op << uri
|
|
@@ -553,17 +614,18 @@ module Squared
|
|
|
553
614
|
exception = true
|
|
554
615
|
banner = false
|
|
555
616
|
end
|
|
556
|
-
|
|
557
|
-
|
|
617
|
+
run(cmd, sync: sync, exception: exception, banner: banner, from: from).tap do |ret|
|
|
618
|
+
success?(ret, flag == :tag || flag == :save)
|
|
619
|
+
end
|
|
558
620
|
end
|
|
559
621
|
|
|
560
622
|
def network(flag, opts = [], target: nil)
|
|
561
623
|
cmd, opts = docker_session('network', flag, opts: opts)
|
|
562
|
-
|
|
563
|
-
|
|
624
|
+
OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, project: self)
|
|
625
|
+
.clear
|
|
564
626
|
from = :"network:#{flag}"
|
|
565
627
|
list_image(flag, docker_output('ps -a'), from: from) do |img|
|
|
566
|
-
|
|
628
|
+
success?(run(cmd.temp(target, img), from: from))
|
|
567
629
|
end
|
|
568
630
|
end
|
|
569
631
|
|
|
@@ -590,10 +652,10 @@ module Squared
|
|
|
590
652
|
def dockerfile(val = nil)
|
|
591
653
|
if val
|
|
592
654
|
@file = if val.is_a?(Array)
|
|
593
|
-
val = val.select { |file|
|
|
655
|
+
val = val.select { |file| exist?(file) }
|
|
594
656
|
val.size > 1 ? val : val.first
|
|
595
657
|
elsif val == true
|
|
596
|
-
DIR_DOCKER.find { |file|
|
|
658
|
+
DIR_DOCKER.find { |file| exist?(file) }
|
|
597
659
|
elsif val != 'Dockerfile'
|
|
598
660
|
val
|
|
599
661
|
end
|
|
@@ -622,8 +684,7 @@ module Squared
|
|
|
622
684
|
return session('docker', *cmd) unless opts
|
|
623
685
|
|
|
624
686
|
op = OptionPartition.new(opts, OPT_DOCKER[:common], project: self)
|
|
625
|
-
|
|
626
|
-
[ret, op.extras]
|
|
687
|
+
[session('docker', *op.to_a, *cmd), op.extras]
|
|
627
688
|
end
|
|
628
689
|
|
|
629
690
|
def docker_output(*cmd, **kwargs)
|
|
@@ -633,8 +694,8 @@ module Squared
|
|
|
633
694
|
def append_command(flag, val, list, target: @session, prompt: ':')
|
|
634
695
|
if list.delete(prompt)
|
|
635
696
|
list << readline('Enter command [args]', force: flag == :exec)
|
|
636
|
-
|
|
637
|
-
list << args
|
|
697
|
+
else
|
|
698
|
+
env('DOCKER_ARGS') { |args| list << args }
|
|
638
699
|
end
|
|
639
700
|
case flag
|
|
640
701
|
when :run
|
|
@@ -642,7 +703,7 @@ module Squared
|
|
|
642
703
|
target << basic_option('name', dnsname("#{name}_%s" % rand_s(6)))
|
|
643
704
|
end
|
|
644
705
|
when :exec
|
|
645
|
-
raise_error
|
|
706
|
+
raise_error ArgumentError, 'nothing to execute', hint: flag if list.empty?
|
|
646
707
|
end
|
|
647
708
|
target << val << list.shift
|
|
648
709
|
target << list.join(' && ') unless list.empty?
|
|
@@ -694,17 +755,45 @@ module Squared
|
|
|
694
755
|
end
|
|
695
756
|
end
|
|
696
757
|
|
|
697
|
-
def
|
|
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)
|
|
698
788
|
pwd_set do
|
|
699
|
-
|
|
700
|
-
index = 0
|
|
789
|
+
index = 1
|
|
701
790
|
all = option('all', prefix: 'docker')
|
|
702
791
|
y = from == :'image:rm' && option('y', prefix: 'docker')
|
|
703
792
|
pat = /\b(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':', 2).first})\b/
|
|
704
|
-
IO.popen(
|
|
793
|
+
IO.popen(cmd.temp('--format=json')).each do |line|
|
|
705
794
|
data = JSON.parse(line)
|
|
706
795
|
id = data['ID']
|
|
707
|
-
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(':')
|
|
708
797
|
rt = nil if rt.empty?
|
|
709
798
|
aa = data['Names'] || (if rt && data['Repository']
|
|
710
799
|
dd = true
|
|
@@ -716,16 +805,16 @@ module Squared
|
|
|
716
805
|
next unless all || ee.match?(pat) || aa.match?(pat)
|
|
717
806
|
|
|
718
807
|
unless y
|
|
719
|
-
bb = index.
|
|
720
|
-
cc = bb.size
|
|
808
|
+
bb = index.to_s
|
|
809
|
+
cc = bb.size.succ
|
|
721
810
|
a = sub_style(ee, styles: theme[:inline])
|
|
722
|
-
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)}"
|
|
723
812
|
e = time_format(time_since(data['CreatedAt']), pass: ['ms'])
|
|
724
813
|
f = sub_style(ARG[:BORDER][0], styles: theme[:inline])
|
|
725
|
-
g = ' ' *
|
|
814
|
+
g = ' ' * cc.succ
|
|
726
815
|
h = "#{sub_style(bb.rjust(cc), styles: theme[:current])} #{f} "
|
|
727
|
-
puts unless index ==
|
|
728
|
-
puts
|
|
816
|
+
puts unless index == 1
|
|
817
|
+
puts (h + sub_style(aa, styles: theme[:subject])).subhint("created #{e} ago")
|
|
729
818
|
cols = %w[Tag Status Ports]
|
|
730
819
|
cols << case flag
|
|
731
820
|
when :connect, :disconnect
|
|
@@ -740,89 +829,104 @@ module Squared
|
|
|
740
829
|
end
|
|
741
830
|
w = 9 + flag.to_s.size + 4 + ee.size
|
|
742
831
|
puts g + sub_style(ARG[:BORDER][6] + (ARG[:BORDER][1] * w), styles: theme[:inline])
|
|
743
|
-
found = true
|
|
744
832
|
index += 1
|
|
745
|
-
next unless confirm("#{h + b}?", no ? 'N' : 'Y'
|
|
833
|
+
next unless confirm("#{h + b}?", no ? 'N' : 'Y')
|
|
746
834
|
|
|
747
835
|
puts if printfirst?
|
|
748
836
|
end
|
|
749
837
|
yield id
|
|
750
838
|
end
|
|
751
|
-
|
|
839
|
+
list_empty(hint: hint || from) if index == 1 && !y
|
|
752
840
|
end
|
|
753
841
|
rescue StandardError => e
|
|
754
842
|
on_error e, from
|
|
755
843
|
end
|
|
756
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
|
+
|
|
757
850
|
def confirm_command(*args, title: nil, target: nil, as: nil)
|
|
758
851
|
return false unless title && target
|
|
759
852
|
|
|
760
853
|
puts unless printfirst?
|
|
761
854
|
t = title.to_s.split(':')
|
|
762
855
|
emphasize(args, title: message(t.first.upcase, *t.drop(1)), border: borderstyle, sub: [
|
|
763
|
-
|
|
764
|
-
|
|
856
|
+
opt_style(theme[:header], /\A(\w+(?: => \w+)+)(.*)\z/),
|
|
857
|
+
opt_style(theme[:caution], /\A(.+)\z/)
|
|
765
858
|
])
|
|
766
859
|
printsucc
|
|
767
860
|
a = t.last.capitalize
|
|
768
861
|
b = sub_style(target, styles: theme[:subject])
|
|
769
862
|
c = as && sub_style(as, styles: theme[:inline])
|
|
770
|
-
confirm
|
|
771
|
-
end
|
|
772
|
-
|
|
773
|
-
def choice_command(flag)
|
|
774
|
-
msg, cmd
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
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
|
|
784
883
|
lines = `#{docker_output(cmd)}`.lines
|
|
785
884
|
header = lines.shift
|
|
786
885
|
if lines.empty?
|
|
787
|
-
puts log_message(Logger::INFO, 'none found', subject: name,
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
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
|
|
821
923
|
end
|
|
822
|
-
|
|
823
|
-
cmd <<
|
|
824
|
-
print_success if success?(run(cmd), ctx.start_with?(/(?:network|tag|save)/))
|
|
924
|
+
else
|
|
925
|
+
cmd << opts << '--'
|
|
825
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)/))
|
|
826
930
|
end
|
|
827
931
|
|
|
828
932
|
def filetype(val = dockerfile)
|
|
@@ -851,10 +955,9 @@ module Squared
|
|
|
851
955
|
|
|
852
956
|
def tagname(val)
|
|
853
957
|
val = val.split(':').map! { |s| charname(s.sub(/^\W+/, '')) }
|
|
854
|
-
val.join(':')
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
end
|
|
958
|
+
ret = val.join(':')
|
|
959
|
+
ret = val.first if val.size > 1 && ret.size > 128
|
|
960
|
+
ret[0..127]
|
|
858
961
|
end
|
|
859
962
|
|
|
860
963
|
def dnsname(val)
|