squared 0.4.42 → 0.5.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 +64 -613
- data/README.md +1283 -663
- data/README.ruby.md +722 -0
- data/lib/squared/common/base.rb +8 -17
- data/lib/squared/common/format.rb +26 -39
- data/lib/squared/common/prompt.rb +48 -53
- data/lib/squared/common/shell.rb +51 -78
- data/lib/squared/common/system.rb +34 -38
- data/lib/squared/common/utils.rb +4 -37
- data/lib/squared/common.rb +2 -1
- data/lib/squared/config.rb +30 -33
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +84 -132
- data/lib/squared/workspace/project/base.rb +437 -601
- data/lib/squared/workspace/project/docker.rb +201 -244
- data/lib/squared/workspace/project/git.rb +392 -543
- data/lib/squared/workspace/project/node.rb +197 -317
- data/lib/squared/workspace/project/python.rb +126 -357
- data/lib/squared/workspace/project/ruby.rb +260 -343
- data/lib/squared/workspace/project/support/class.rb +94 -341
- data/lib/squared/workspace/project.rb +0 -10
- data/lib/squared/workspace/repo.rb +59 -100
- data/lib/squared/workspace/series.rb +42 -49
- data/lib/squared/workspace/support/data.rb +3 -2
- data/lib/squared/workspace/support.rb +0 -1
- data/lib/squared/workspace.rb +3 -5
- data/squared.gemspec +5 -5
- metadata +7 -8
- data/lib/squared/common/class.rb +0 -186
- data/lib/squared/workspace/support/base.rb +0 -32
|
@@ -4,83 +4,76 @@ module Squared
|
|
|
4
4
|
module Workspace
|
|
5
5
|
module Project
|
|
6
6
|
class Docker < Base
|
|
7
|
-
COMPOSEFILE = %w[compose.yaml compose.yml docker-compose.yaml docker-compose.yml].freeze
|
|
7
|
+
COMPOSEFILE = %w[compose.yaml compose.yml docker-compose.yaml compose.yml docker-compose.yml].freeze
|
|
8
8
|
BAKEFILE = %w[docker-bake.json docker-bake.hcl docker-bake.override.json docker-bake.override.hcl].freeze
|
|
9
|
-
DIR_DOCKER = (COMPOSEFILE + BAKEFILE
|
|
9
|
+
DIR_DOCKER = (COMPOSEFILE + BAKEFILE).freeze
|
|
10
10
|
OPT_DOCKER = {
|
|
11
11
|
common: %w[tls tlsverify config=p c|context=b D|debug H|host=q l|log-level=b tlscacert=p tlscert=p
|
|
12
12
|
tlskey=p].freeze,
|
|
13
13
|
buildx: {
|
|
14
14
|
common: %w[builder=b D|debug],
|
|
15
|
-
build: %w[add-host=q annotation=q attest=q build-arg=qq
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
bake: %w[print list=q set=q].freeze,
|
|
19
|
-
shared: %w[check
|
|
20
|
-
sbom=b?].freeze
|
|
15
|
+
build: %w[load pull push add-host=q annotation=q attest=q build-arg=qq ent=q iidfile=p label=q a-file=p
|
|
16
|
+
network=b no-cache-filter=b o|output=q platform=b q|quiet secret=qq shm-size=b ssh=qq t|tag=b
|
|
17
|
+
target=b ulimit=q].freeze,
|
|
18
|
+
bake: %w[load print pull push list=q metadata-file=p set=q].freeze,
|
|
19
|
+
shared: %w[check no-cache allow=q call=b? f|file=p progress=b provenance=q sbom=q].freeze
|
|
21
20
|
}.freeze,
|
|
22
21
|
compose: {
|
|
23
|
-
common: %w[
|
|
24
|
-
project-directory=p p|project-name=
|
|
25
|
-
build: %w[
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
exit-code-from=b no-attach=b pull=b scale=i t|timeout=i wait-timeout=i].freeze,
|
|
35
|
-
down: %w[remove-orphans v|volumes rmi=b t|timeout=i].freeze
|
|
22
|
+
common: %w[all-resources compatibility dry-run ansi|b env-file=p f|file=p parallel=b profile=b progress=b
|
|
23
|
+
project-directory=p p|project-name=e].freeze,
|
|
24
|
+
build: %w[no-cache pull push with-dependencies q|quiet build-arg=qq builder=b m|memory=b ssh=qq].freeze,
|
|
25
|
+
exec: %w[dry-run privileged d|detach e|env=qq index=i T|no-TTY=b? user=e w|workdir=q].freeze,
|
|
26
|
+
run: %w[build dry-run no-deps quiet-pull remove-orphans rm P|service-ports use-aliases cap-add=b cap-drop=b
|
|
27
|
+
d|detach entrypoint=q e|env=qq i|interactive=b? l|label=q name=b T|no-TTY=b? p|publish=e pull=b
|
|
28
|
+
u|user=e v|volume=q w|workdir=q].freeze,
|
|
29
|
+
up: %w[y abort-on-container-exit abort-on-container-failure always-recreate-deps attach-dependencies build
|
|
30
|
+
d|detach dry-run force-recreate menu no-build no-color no-deps no-log-prefix no-recreate no-start
|
|
31
|
+
quiet-pull remove-orphans V|renew-anon-volumes timestamps wait w|watch attach=b exit-code-from=b
|
|
32
|
+
no-attach=b pull=b scale=i t|timeout=i wait-timeout=i].freeze
|
|
36
33
|
}.freeze,
|
|
37
34
|
container: {
|
|
38
35
|
create: %w[init i|interactive no-healthcheck oom-kill-disable privileged P|publish-all q|quiet read-only
|
|
39
|
-
rm t|tty
|
|
40
|
-
blkio-weight-device=i cap-add=b cap-drop=b cgroup-parent=b cgroupns=b
|
|
41
|
-
device-cgroup-rule=q device-read-bps=q device-read-iops=q device-write-bps=q
|
|
42
|
-
disable-content-trust=b? dns=
|
|
43
|
-
env-file=p expose=
|
|
44
|
-
health-start-interval=
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
memory-
|
|
48
|
-
|
|
49
|
-
stop-
|
|
50
|
-
|
|
36
|
+
rm runtime t|tty use-api-socket io-maxbandwidth=b io-maxiops=b add-host=q annotation=q
|
|
37
|
+
a|attach=b blkio-weight=i blkio-weight-device=i cap-add=b cap-drop=b cgroup-parent=b cgroupns=b
|
|
38
|
+
cidfile=p device=q device-cgroup-rule=q device-read-bps=q device-read-iops=q device-write-bps=q
|
|
39
|
+
device-write-iops=q disable-content-trust=b? dns=e dns-option=e dns-search=e domainname=b
|
|
40
|
+
entrypoint=q e|env=qq env-file=p expose=e gpus=q group-add=b health-cmd=q health-interval=b
|
|
41
|
+
health-retries=i health-start-interval=b health-start-period=b health-timeout=b h|hostname=e ip=b
|
|
42
|
+
ip6=e ipc=b isolation=b kernel-memory=b l|label=q label-file=p link=b link-local-ip=b
|
|
43
|
+
log-driver=b log-opt=q mac-address=e m|memory=b memory-reservation=b memory-swap=n
|
|
44
|
+
memory-swappiness=n mount=qq name=b network=b network-alias=b oom-score-adj=b pid=b pids-limit=n
|
|
45
|
+
platform=b p|publish=e pull=b restart=b runtime=b security-opt=q shm-size=b stop-signal=b
|
|
46
|
+
stop-timeout=i storage-opt=q sysctl=q tmpfs=q ulimit=q u|user=b userns=b uts=b v|volume=q
|
|
47
|
+
volume-driver=b volumes-from=b w|workdir=q].freeze,
|
|
51
48
|
run: %w[d|detach detach-keys=q sig-proxy=b?].freeze,
|
|
49
|
+
exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p user=e
|
|
50
|
+
w|workdir=q].freeze,
|
|
52
51
|
update: %w[blkio-weight=i cpu-period=i cpu-quota=i cpu-rt-period=i cpu-rt-runtime=i c|cpu-shares=i cpus=f
|
|
53
52
|
cpuset-cpus=b cpuset-mems=b m|memory=b memory-reservation=b memory-swap=b pids-limit=n
|
|
54
53
|
restart=q].freeze,
|
|
55
|
-
exec: %w[d|detach i|interactive privileged t|tty=!? detach-keys=q e|env=qq env-file=p user=b
|
|
56
|
-
w|workdir=q].freeze,
|
|
57
|
-
rm: %w[f|force l|link v|volumes].freeze,
|
|
58
54
|
commit: %w[a|author=q c|change=q m|message=q pause=b?].freeze,
|
|
59
|
-
inspect: %w[s|size f|format=q
|
|
55
|
+
inspect: %w[s|size f|format=q].freeze,
|
|
60
56
|
start: %w[a|attach i|interactive detach-keys=q].freeze,
|
|
61
|
-
stop: %w[s|signal=b t|time=i
|
|
62
|
-
restart: %w[s|signal=b t|time=i
|
|
57
|
+
stop: %w[s|signal=b t|time=i].freeze,
|
|
58
|
+
restart: %w[s|signal=b t|time=i].freeze,
|
|
63
59
|
kill: %w[s|signal=b].freeze,
|
|
64
|
-
stats: %w[
|
|
60
|
+
stats: %w[no-trunc format|q].freeze
|
|
65
61
|
}.freeze,
|
|
66
62
|
image: {
|
|
67
|
-
list: %w[a|all
|
|
68
|
-
push: %w[a|all-tags disable-content-trust=b? platform=
|
|
69
|
-
rm: %w[f|force no-prune
|
|
70
|
-
save: %w[o|output=p platform=
|
|
63
|
+
list: %w[a|all digests no-trunc f|filter=q format=q].freeze,
|
|
64
|
+
push: %w[a|all-tags disable-content-trust=b? platform=b q|quiet].freeze,
|
|
65
|
+
rm: %w[f|force no-prune].freeze,
|
|
66
|
+
save: %w[o|output=p platform=b].freeze
|
|
71
67
|
}.freeze,
|
|
72
68
|
network: {
|
|
73
|
-
connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=
|
|
69
|
+
connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=b link=b link-local-ip=b].freeze,
|
|
74
70
|
disconnect: %w[f|force].freeze
|
|
75
71
|
}.freeze
|
|
76
72
|
}.freeze
|
|
77
73
|
VAL_DOCKER = {
|
|
78
74
|
run: {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
volume: %w[volume-subpath volume-nocopy volume-opt].freeze,
|
|
82
|
-
tmpfs: %w[tmpfs-size tmpfs-mode].freeze,
|
|
83
|
-
image: %w[image-subpath].freeze
|
|
75
|
+
bind: %w[type source src destination dst target readonly ro bind-propagation].freeze,
|
|
76
|
+
tmpfs: %w[type destination dst target tmpfs-size tmpfs-mode].freeze
|
|
84
77
|
}.freeze
|
|
85
78
|
}.freeze
|
|
86
79
|
private_constant :COMPOSEFILE, :BAKEFILE, :OPT_DOCKER, :VAL_DOCKER
|
|
@@ -93,14 +86,13 @@ module Squared
|
|
|
93
86
|
def config?(val)
|
|
94
87
|
return false unless (val = as_path(val))
|
|
95
88
|
|
|
96
|
-
DIR_DOCKER.any? { |file| val.join(file).exist? }
|
|
89
|
+
val.join('Dockerfile').exist? || DIR_DOCKER.any? { |file| val.join(file).exist? }
|
|
97
90
|
end
|
|
98
91
|
end
|
|
99
92
|
|
|
100
93
|
subtasks({
|
|
101
|
-
'build' => %i[tag context].freeze,
|
|
102
|
-
'compose' => %i[build run exec up
|
|
103
|
-
'bake' => %i[build check].freeze,
|
|
94
|
+
'build' => %i[tag context bake].freeze,
|
|
95
|
+
'compose' => %i[build run exec up].freeze,
|
|
104
96
|
'image' => %i[list rm push tag save].freeze,
|
|
105
97
|
'container' => %i[run create exec update commit inspect diff start stop restart pause unpause top stats kill
|
|
106
98
|
rm].freeze,
|
|
@@ -115,10 +107,11 @@ module Squared
|
|
|
115
107
|
return unless dockerfile(file).exist?
|
|
116
108
|
|
|
117
109
|
@context = context
|
|
118
|
-
|
|
110
|
+
@tag = tag || tagname("#{@project}:#{@version || 'latest'}")
|
|
119
111
|
@mounts = mounts
|
|
120
112
|
@secrets = secrets
|
|
121
113
|
@registry = tagjoin registry, kwargs[:username]
|
|
114
|
+
@file = nil
|
|
122
115
|
initialize_ref Docker.ref
|
|
123
116
|
initialize_logger(**kwargs)
|
|
124
117
|
initialize_env(**kwargs)
|
|
@@ -131,11 +124,11 @@ module Squared
|
|
|
131
124
|
|
|
132
125
|
def populate(*, **)
|
|
133
126
|
super
|
|
134
|
-
return unless ref?(Docker.ref)
|
|
127
|
+
return unless ref?(Docker.ref)
|
|
135
128
|
|
|
136
129
|
namespace name do
|
|
137
130
|
Docker.subtasks do |action, flags|
|
|
138
|
-
next if
|
|
131
|
+
next if @pass.include?(action)
|
|
139
132
|
|
|
140
133
|
namespace action do
|
|
141
134
|
flags.each do |flag|
|
|
@@ -148,39 +141,26 @@ module Squared
|
|
|
148
141
|
param = param_guard(action, flag, args: args, key: flag)
|
|
149
142
|
buildx(:build, args.extras, "#{flag}": param)
|
|
150
143
|
end
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
break unless bake?
|
|
154
|
-
|
|
155
|
-
case flag
|
|
156
|
-
when :build
|
|
157
|
-
format_desc action, flag, 'opts*,target*,context?|:'
|
|
144
|
+
when :bake
|
|
145
|
+
format_desc action, flag, ':?,opts*,target*,context?'
|
|
158
146
|
task flag do |_, args|
|
|
159
147
|
args = args.to_a
|
|
160
148
|
if args.first == ':'
|
|
161
149
|
choice_command :bake
|
|
162
150
|
else
|
|
163
|
-
buildx
|
|
151
|
+
buildx flag, args
|
|
164
152
|
end
|
|
165
153
|
end
|
|
166
|
-
when :check
|
|
167
|
-
format_desc action, flag, 'target'
|
|
168
|
-
task flag, [:target] do |_, args|
|
|
169
|
-
target = param_guard(action, flag, args: args, key: :target)
|
|
170
|
-
buildx :bake, ['allow=fs.read=*', 'call=check', target]
|
|
171
|
-
end
|
|
172
154
|
end
|
|
173
155
|
when 'compose'
|
|
174
|
-
break unless compose?
|
|
175
|
-
|
|
176
156
|
case flag
|
|
177
|
-
when :build, :up
|
|
157
|
+
when :build, :up
|
|
178
158
|
format_desc action, flag, 'opts*,service*'
|
|
179
159
|
task flag do |_, args|
|
|
180
160
|
compose! flag, args.to_a
|
|
181
161
|
end
|
|
182
162
|
when :exec, :run
|
|
183
|
-
format_desc action, flag, "service,command#{flag == :exec ? '' : '?'}
|
|
163
|
+
format_desc action, flag, "service,command#{flag == :exec ? '' : '?'},args*,opts*"
|
|
184
164
|
task flag, [:service] do |_, args|
|
|
185
165
|
service = param_guard(action, flag, args: args, key: :service)
|
|
186
166
|
compose!(flag, args.extras, service: service)
|
|
@@ -208,7 +188,7 @@ module Squared
|
|
|
208
188
|
end
|
|
209
189
|
end
|
|
210
190
|
else
|
|
211
|
-
format_desc
|
|
191
|
+
format_desc(action, flag, 'opts*,id/name', after: flag == :update ? '+' : '*')
|
|
212
192
|
task flag do |_, args|
|
|
213
193
|
container flag, args.to_a
|
|
214
194
|
end
|
|
@@ -218,15 +198,14 @@ module Squared
|
|
|
218
198
|
when :push
|
|
219
199
|
format_desc action, flag, 'tag,registry/username?,opts*'
|
|
220
200
|
task flag, [:tag] do |_, args|
|
|
221
|
-
|
|
222
|
-
image(flag, args.extras, id:
|
|
201
|
+
id = param_guard(action, flag, args: args, key: :tag)
|
|
202
|
+
image(flag, args.extras, id: id)
|
|
223
203
|
end
|
|
224
204
|
else
|
|
225
205
|
format_desc(action, flag, case flag
|
|
226
206
|
when :rm, :save then 'id*,opts*'
|
|
227
207
|
when :tag then 'version?'
|
|
228
|
-
else 'opts*,args*'
|
|
229
|
-
end)
|
|
208
|
+
else 'opts*,args*' end)
|
|
230
209
|
task flag do |_, args|
|
|
231
210
|
args = args.to_a
|
|
232
211
|
if args.empty? && flag != :list
|
|
@@ -253,44 +232,43 @@ module Squared
|
|
|
253
232
|
end
|
|
254
233
|
|
|
255
234
|
def clean(*, sync: invoked_sync?('clean'), **)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
image :rm
|
|
260
|
-
end
|
|
235
|
+
return super unless @clean.nil?
|
|
236
|
+
|
|
237
|
+
image(:rm, sync: sync)
|
|
261
238
|
end
|
|
262
239
|
|
|
263
240
|
def compose(opts, flags = nil, script: false, args: nil, from: :run, **)
|
|
264
241
|
return opts if script == false
|
|
265
242
|
|
|
243
|
+
ret = docker_session
|
|
266
244
|
if from == :run
|
|
267
|
-
|
|
268
|
-
|
|
245
|
+
case (n = filetype)
|
|
246
|
+
when 1, 2
|
|
247
|
+
ret << 'buildx' << 'bake'
|
|
269
248
|
append_file n
|
|
270
249
|
from = :bake
|
|
271
|
-
|
|
272
|
-
ret
|
|
250
|
+
when 3, 4
|
|
251
|
+
ret << 'compose' << 'build'
|
|
273
252
|
append_file n
|
|
274
253
|
from = :compose
|
|
275
254
|
else
|
|
276
|
-
ret
|
|
255
|
+
ret << 'build'
|
|
277
256
|
end
|
|
278
257
|
else
|
|
279
|
-
ret
|
|
258
|
+
ret << from
|
|
280
259
|
end
|
|
281
260
|
case opts
|
|
282
261
|
when String
|
|
283
262
|
ret << opts
|
|
284
263
|
when Hash
|
|
285
|
-
ret.merge(append_hash(opts,
|
|
264
|
+
ret.merge(append_hash(opts, build: true))
|
|
286
265
|
when Enumerable
|
|
287
266
|
ret.merge(opts.to_a)
|
|
288
267
|
end
|
|
268
|
+
|
|
289
269
|
[args, flags].each_with_index do |target, index|
|
|
290
|
-
if target
|
|
291
|
-
ret
|
|
292
|
-
elsif (target = append_any(target, target: []))
|
|
293
|
-
ret.merge(target.map { |arg| index == 0 ? fill_option(arg) : quote_option('build-arg', arg) })
|
|
270
|
+
if (data = append_any(target, target: []))
|
|
271
|
+
ret.merge(data.map { |arg| index == 0 ? fill_option(arg) : quote_option('build-arg', arg) })
|
|
294
272
|
end
|
|
295
273
|
end
|
|
296
274
|
case from
|
|
@@ -300,12 +278,12 @@ module Squared
|
|
|
300
278
|
ret << quote_option('secret', @secrets, double: true)
|
|
301
279
|
when Hash
|
|
302
280
|
append = lambda do |type|
|
|
303
|
-
|
|
281
|
+
as_a(@secrets[type]).each { |arg| ret << quote_option('secret', "type=#{type},#{arg}", double: true) }
|
|
304
282
|
end
|
|
305
283
|
append.call(:file)
|
|
306
284
|
append.call(:env)
|
|
307
285
|
else
|
|
308
|
-
|
|
286
|
+
as_a(@secrets).each { |arg| ret << quote_option('secret', arg) }
|
|
309
287
|
end
|
|
310
288
|
if (val = option('tag', ignore: false))
|
|
311
289
|
append_tag val
|
|
@@ -314,8 +292,8 @@ module Squared
|
|
|
314
292
|
end
|
|
315
293
|
append_context
|
|
316
294
|
when :bake, :compose
|
|
317
|
-
|
|
318
|
-
ret.merge(split_escape(
|
|
295
|
+
option(from == :bake ? 'target' : 'service', ignore: false) do |a|
|
|
296
|
+
ret.merge(split_escape(a).map! { |b| shell_escape(b) })
|
|
319
297
|
end
|
|
320
298
|
end
|
|
321
299
|
ret
|
|
@@ -328,11 +306,22 @@ module Squared
|
|
|
328
306
|
op.parse(OPT_DOCKER[:buildx][flag == :bake ? :bake : :build] + OPT_DOCKER[:buildx][:shared])
|
|
329
307
|
case flag
|
|
330
308
|
when :build, :context
|
|
331
|
-
append_tag(tag || option('tag', ignore: false) ||
|
|
309
|
+
append_tag(tag || option('tag', ignore: false) || @tag)
|
|
332
310
|
append_context context
|
|
333
311
|
when :bake
|
|
334
|
-
op.
|
|
335
|
-
|
|
312
|
+
unless op.empty?
|
|
313
|
+
args = op.dup
|
|
314
|
+
op.extras.clear
|
|
315
|
+
if Dir.exist?(args.last)
|
|
316
|
+
if projectpath?(val = args.pop)
|
|
317
|
+
context = val
|
|
318
|
+
else
|
|
319
|
+
op.extras << val
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
op.append(args, escape: true)
|
|
323
|
+
contextdir context if context
|
|
324
|
+
end
|
|
336
325
|
end
|
|
337
326
|
op.clear(pass: false)
|
|
338
327
|
run(from: :"buildx:#{flag}")
|
|
@@ -343,16 +332,16 @@ module Squared
|
|
|
343
332
|
op = OptionPartition.new(opts, OPT_DOCKER[:compose][:common], cmd, project: self)
|
|
344
333
|
append_file filetype unless op.arg?('f', 'file')
|
|
345
334
|
op << flag
|
|
346
|
-
op.parse(OPT_DOCKER[:compose]
|
|
335
|
+
op.parse(OPT_DOCKER[:compose][flag])
|
|
336
|
+
from = :"compose:#{flag}"
|
|
347
337
|
case flag
|
|
348
|
-
when :build, :up
|
|
349
|
-
op.append(escape: true
|
|
338
|
+
when :build, :up
|
|
339
|
+
op.append(escape: true)
|
|
350
340
|
when :exec, :run
|
|
351
|
-
append_command
|
|
341
|
+
append_command(flag, service, op.extras, from: from)
|
|
352
342
|
end
|
|
353
|
-
run(from:
|
|
343
|
+
run(from: from)
|
|
354
344
|
end
|
|
355
|
-
alias compose_ compose!
|
|
356
345
|
|
|
357
346
|
def container(flag, opts = [], id: nil)
|
|
358
347
|
cmd, opts = docker_session('container', flag, opts: opts)
|
|
@@ -365,64 +354,45 @@ module Squared
|
|
|
365
354
|
case flag
|
|
366
355
|
when :run, :create, :exec
|
|
367
356
|
if rc && !op.arg?('mount')
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
357
|
+
run = VAL_DOCKER[:run]
|
|
358
|
+
both = run[:bind] + run[:tmpfs]
|
|
359
|
+
diff = run[:bind].reject { |val| run[:tmpfs].include?(val) }
|
|
360
|
+
delim = Regexp.new(",\\s*(?=#{both.join('|')})")
|
|
361
|
+
as_a(@mounts).each do |val|
|
|
371
362
|
args = []
|
|
372
|
-
|
|
363
|
+
tmpfs = true
|
|
373
364
|
val.split(delim).each do |opt|
|
|
374
365
|
k, v, q = split_option opt
|
|
375
|
-
|
|
376
|
-
case v
|
|
377
|
-
when 'bind', 'volume', 'image', 'tmpfs'
|
|
378
|
-
type = v
|
|
379
|
-
else
|
|
380
|
-
raise_error("unknown type: #{v}", hint: flag)
|
|
381
|
-
end
|
|
382
|
-
elsif all.include?(k)
|
|
383
|
-
unless type
|
|
384
|
-
VAL_DOCKER[:run].each_pair do |key, a|
|
|
385
|
-
next unless a.include?(k)
|
|
366
|
+
next unless both.include?(k)
|
|
386
367
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
elsif type == 'tmpfs'
|
|
402
|
-
next
|
|
403
|
-
end
|
|
404
|
-
when 'destination', 'dst', 'target'
|
|
405
|
-
puts log_message("path is not absolute: #{v}", subject: from, hint: k) unless v.start_with?('/')
|
|
406
|
-
end
|
|
407
|
-
v = shell_quote(v, option: false, force: false) if q == ''
|
|
408
|
-
end
|
|
409
|
-
args << "#{k}=#{q + v + q}"
|
|
410
|
-
elsif verbose
|
|
411
|
-
puts log_message(Logger::INFO, 'unrecognized option', subject: from, hint: k)
|
|
368
|
+
if k == 'type'
|
|
369
|
+
tmpfs = false if v == 'bind'
|
|
370
|
+
next
|
|
371
|
+
elsif diff.include?(k)
|
|
372
|
+
tmpfs = false
|
|
373
|
+
end
|
|
374
|
+
case k
|
|
375
|
+
when 'readonly', 'ro'
|
|
376
|
+
args << k
|
|
377
|
+
next
|
|
378
|
+
when 'source', 'src', 'destination', 'dst', 'target'
|
|
379
|
+
v = path + v
|
|
380
|
+
v = shell_quote(v, option: false, force: false) if q == ''
|
|
381
|
+
tmpfs = false if k[0] == 's'
|
|
412
382
|
end
|
|
383
|
+
args << "#{k}=#{q + v + q}"
|
|
413
384
|
end
|
|
414
|
-
|
|
415
|
-
op << "--mount type=#{type},#{args.join(',')}"
|
|
385
|
+
cmd << "--mount type=#{tmpfs ? 'tmpfs' : 'bind'},#{args.join(',')}"
|
|
416
386
|
end
|
|
417
387
|
end
|
|
418
|
-
append_command(flag, id || tagmain, op.extras)
|
|
419
|
-
when :update
|
|
420
|
-
raise_error('missing container', hint:
|
|
421
|
-
op.append(escape: true
|
|
388
|
+
append_command(flag, id || tagmain, op.extras, from: from)
|
|
389
|
+
when :update
|
|
390
|
+
raise_error('missing container', hint: from) if op.empty?
|
|
391
|
+
op.append(escape: true)
|
|
422
392
|
when :commit
|
|
423
393
|
latest = op.shift || tagmain
|
|
424
|
-
|
|
425
|
-
raise_error("unknown args: #{op.join(', ')}", hint:
|
|
394
|
+
cmd << id << latest
|
|
395
|
+
raise_error("unknown args: #{op.join(', ')}", hint: from) unless op.empty?
|
|
426
396
|
return unless confirm_command(cmd.to_s, title: from, target: id, as: latest)
|
|
427
397
|
|
|
428
398
|
registry = option('registry') || @registry
|
|
@@ -465,13 +435,13 @@ module Squared
|
|
|
465
435
|
when :rm
|
|
466
436
|
status = %w[created exited dead]
|
|
467
437
|
end
|
|
468
|
-
ps = docker_output('ps -a', *status.map { |s|
|
|
438
|
+
ps = docker_output('ps -a', *status.map { |s| "--filter=\"status=#{s}\"" })
|
|
469
439
|
list_image(flag, ps, no: no, hint: "status: #{status.join(', ')}", from: from) do |img|
|
|
470
440
|
run(cmd.temp(img), from: from)
|
|
471
441
|
end
|
|
472
442
|
return
|
|
473
443
|
else
|
|
474
|
-
op.append(escape: true
|
|
444
|
+
op.append(escape: true)
|
|
475
445
|
end
|
|
476
446
|
end
|
|
477
447
|
run(from: from)
|
|
@@ -522,17 +492,17 @@ module Squared
|
|
|
522
492
|
list_image(flag, docker_output('image ls -a'), from: from) do |val|
|
|
523
493
|
op << val
|
|
524
494
|
if flag == :tag
|
|
525
|
-
op << tagname("#{project}:#{op.first}")
|
|
495
|
+
op << tagname("#{@project}:#{op.extras.first}")
|
|
526
496
|
break
|
|
527
497
|
end
|
|
528
498
|
end
|
|
529
499
|
when :push
|
|
530
500
|
id ||= option('tag', ignore: false) || tagmain
|
|
531
501
|
registry ||= op.shift || option('registry') || @registry
|
|
532
|
-
raise_error(id ? "unknown args: #{op.join(', ')}" : 'no id/tag given', hint:
|
|
533
|
-
raise_error('username/registry not provided', hint:
|
|
502
|
+
raise_error(id ? "unknown args: #{op.join(', ')}" : 'no id/tag given', hint: from) unless id && op.empty?
|
|
503
|
+
raise_error('username/registry not provided', hint: from) unless registry
|
|
534
504
|
registry.chomp!('/')
|
|
535
|
-
uri = shell_quote
|
|
505
|
+
uri = shell_quote "#{registry}/#{id}"
|
|
536
506
|
op << uri
|
|
537
507
|
img = docker_output 'image', 'tag', id, uri
|
|
538
508
|
return unless confirm_command(img.to_s, cmd.to_s, target: id, as: registry, title: from)
|
|
@@ -548,7 +518,7 @@ module Squared
|
|
|
548
518
|
|
|
549
519
|
def network(flag, opts = [], target: nil)
|
|
550
520
|
cmd, opts = docker_session('network', flag, opts: opts)
|
|
551
|
-
op = OptionPartition.new(opts, OPT_DOCKER[:network]
|
|
521
|
+
op = OptionPartition.new(opts, OPT_DOCKER[:network][flag], cmd, project: self)
|
|
552
522
|
op.clear
|
|
553
523
|
from = :"network:#{flag}"
|
|
554
524
|
list_image(flag, docker_output('ps -a'), from: from) do |img|
|
|
@@ -564,28 +534,17 @@ module Squared
|
|
|
564
534
|
super || dockerfile.exist?
|
|
565
535
|
end
|
|
566
536
|
|
|
567
|
-
def compose?(file = dockerfile)
|
|
568
|
-
return file == 3 || file == 4 if file.is_a?(Numeric)
|
|
569
|
-
|
|
570
|
-
COMPOSEFILE.include?(File.basename(file))
|
|
571
|
-
end
|
|
572
|
-
|
|
573
|
-
def bake?(file = dockerfile)
|
|
574
|
-
return file == 1 || file == 2 if file.is_a?(Numeric)
|
|
575
|
-
|
|
576
|
-
BAKEFILE.include?(File.basename(file))
|
|
577
|
-
end
|
|
578
|
-
|
|
579
537
|
def dockerfile(val = nil)
|
|
580
|
-
if val
|
|
538
|
+
if val == 'Dockerfile'
|
|
539
|
+
@file = false
|
|
540
|
+
elsif val
|
|
581
541
|
@file = if val.is_a?(Array)
|
|
582
542
|
val = val.select { |file| basepath(file).exist? }
|
|
583
543
|
val.size > 1 ? val : val.first
|
|
584
|
-
|
|
585
|
-
DIR_DOCKER.find { |file| basepath(file).exist? }
|
|
586
|
-
elsif val != 'Dockerfile'
|
|
587
|
-
val
|
|
544
|
+
else
|
|
545
|
+
val || DIR_DOCKER.find { |file| basepath(file).exist? }
|
|
588
546
|
end
|
|
547
|
+
@file ||= false
|
|
589
548
|
end
|
|
590
549
|
basepath((@file.is_a?(Array) ? @file.first : @file) || 'Dockerfile')
|
|
591
550
|
end
|
|
@@ -604,56 +563,35 @@ module Squared
|
|
|
604
563
|
session('docker', *cmd, main: false, options: false, **kwargs)
|
|
605
564
|
end
|
|
606
565
|
|
|
607
|
-
def append_command(flag, val, list, target: @session)
|
|
608
|
-
if
|
|
609
|
-
list << readline('Enter command [args]', force: true)
|
|
610
|
-
elsif (args = env('DOCKER_ARGS'))
|
|
566
|
+
def append_command(flag, val, list, target: @session, from: nil)
|
|
567
|
+
if (args = env('DOCKER_ARGS'))
|
|
611
568
|
list << args
|
|
612
569
|
end
|
|
613
570
|
case flag
|
|
614
571
|
when :run
|
|
615
572
|
unless session_arg?('name', target: target)
|
|
616
|
-
target << basic_option('name', dnsname("#{name}_%s" %
|
|
573
|
+
target << basic_option('name', dnsname("#{name}_%s" % if RUBY_VERSION >= '3.1'
|
|
574
|
+
require 'random/formatter'
|
|
575
|
+
Random.new.alphanumeric(6)
|
|
576
|
+
else
|
|
577
|
+
(0...6).map { rand(97..122).chr }.join
|
|
578
|
+
end))
|
|
617
579
|
end
|
|
618
580
|
when :exec
|
|
619
|
-
raise_error('no command args', hint:
|
|
620
|
-
end
|
|
621
|
-
target << val
|
|
622
|
-
case list.first
|
|
623
|
-
when '--'
|
|
624
|
-
target.merge(list.drop(1))
|
|
625
|
-
when /\A(--|&&)(\s|\z)/
|
|
626
|
-
target.merge(list)
|
|
627
|
-
else
|
|
628
|
-
target << list.shift
|
|
629
|
-
unless list.empty?
|
|
630
|
-
if list.first.start_with?('-')
|
|
631
|
-
target.merge(list)
|
|
632
|
-
else
|
|
633
|
-
target << list.join(' && ')
|
|
634
|
-
end
|
|
635
|
-
end
|
|
581
|
+
raise_error('no command args', hint: from) if list.empty?
|
|
636
582
|
end
|
|
583
|
+
target << val << list.shift
|
|
584
|
+
target << list.join(' && ') unless list.empty?
|
|
637
585
|
end
|
|
638
586
|
|
|
639
|
-
def append_file(type, target: @session
|
|
640
|
-
return
|
|
587
|
+
def append_file(type, target: @session)
|
|
588
|
+
return unless type == 2 || type == 4 || @file.is_a?(Array)
|
|
641
589
|
|
|
642
|
-
|
|
643
|
-
case type
|
|
644
|
-
when 2, 4
|
|
645
|
-
return
|
|
646
|
-
when 3
|
|
647
|
-
return unless COMPOSEFILE.select { |val| basepath(val).exist? }.size > 1
|
|
648
|
-
end
|
|
649
|
-
end
|
|
650
|
-
files = Array(@file).map { |val| quote_option('file', basepath(val)) }
|
|
590
|
+
files = as_a(@file).map { |val| quote_option('file', path + val) }
|
|
651
591
|
if target.is_a?(Set)
|
|
652
|
-
|
|
653
|
-
target.clear
|
|
654
|
-
.merge(opts)
|
|
592
|
+
target.merge(files)
|
|
655
593
|
else
|
|
656
|
-
target.
|
|
594
|
+
target.concat(files)
|
|
657
595
|
end
|
|
658
596
|
end
|
|
659
597
|
|
|
@@ -665,28 +603,30 @@ module Squared
|
|
|
665
603
|
end
|
|
666
604
|
|
|
667
605
|
def append_tag(val, target: @session)
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
606
|
+
case val
|
|
607
|
+
when String
|
|
608
|
+
val.split(',')
|
|
609
|
+
when Array
|
|
610
|
+
val
|
|
611
|
+
else
|
|
612
|
+
[]
|
|
613
|
+
end.yield_self do |list|
|
|
614
|
+
ver = option('version', target: target, ignore: false)
|
|
615
|
+
list.each do |s|
|
|
616
|
+
s = "#{s}:#{ver}" if ver && (!s.include?(':') || s.delete_suffix!(':latest'))
|
|
617
|
+
target << basic_option('tag', tagname(s))
|
|
618
|
+
end
|
|
619
|
+
target
|
|
680
620
|
end
|
|
681
621
|
end
|
|
682
622
|
|
|
683
|
-
def list_image(flag, cmd, hint: nil,
|
|
684
|
-
pwd_set
|
|
623
|
+
def list_image(flag, cmd, hint: nil, from: nil, no: true)
|
|
624
|
+
pwd_set do
|
|
685
625
|
found = false
|
|
686
626
|
index = 0
|
|
687
627
|
all = option('all', prefix: 'docker')
|
|
688
628
|
y = from == :'image:rm' && option('y', prefix: 'docker')
|
|
689
|
-
pat =
|
|
629
|
+
pat = /^(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':', 2).first})(?:[_.,:-]|$)/
|
|
690
630
|
IO.popen(session_done(cmd << '--format=json')).each do |line|
|
|
691
631
|
data = JSON.parse(line)
|
|
692
632
|
id = data['ID']
|
|
@@ -723,7 +663,7 @@ module Squared
|
|
|
723
663
|
cols.each do |key|
|
|
724
664
|
next if (key == 'Tag' && !dd) || (key == 'Size' && data[key] == '0B')
|
|
725
665
|
|
|
726
|
-
puts "#{g + f} #{key}: #{
|
|
666
|
+
puts "#{g + f} #{key}: #{as_a(data[key]).join(', ')}" unless data[key].to_s.empty?
|
|
727
667
|
end
|
|
728
668
|
w = 9 + flag.to_s.size + 4 + ee.size
|
|
729
669
|
puts g + sub_style(ARG[:BORDER][6] + (ARG[:BORDER][1] * w), styles: theme[:inline])
|
|
@@ -735,10 +675,14 @@ module Squared
|
|
|
735
675
|
end
|
|
736
676
|
yield id
|
|
737
677
|
end
|
|
738
|
-
puts log_message(Logger::INFO, 'none detected', subject: name, hint: hint
|
|
678
|
+
puts log_message(Logger::INFO, 'none detected', subject: "#{name}:#{from}", hint: hint) if found || y
|
|
739
679
|
end
|
|
740
680
|
rescue StandardError => e
|
|
741
|
-
|
|
681
|
+
log.error e
|
|
682
|
+
ret = on(:error, from, e)
|
|
683
|
+
raise if exception && ret != true
|
|
684
|
+
|
|
685
|
+
warn log_message(Logger::WARN, e, pass: true) if warning?
|
|
742
686
|
end
|
|
743
687
|
|
|
744
688
|
def confirm_command(*args, title: nil, target: nil, as: nil)
|
|
@@ -795,7 +739,7 @@ module Squared
|
|
|
795
739
|
cmd = docker_output ctx
|
|
796
740
|
case flag
|
|
797
741
|
when :tag
|
|
798
|
-
args = tagjoin @registry, tag
|
|
742
|
+
args = tagjoin @registry, @tag
|
|
799
743
|
when :save
|
|
800
744
|
opts = "#{opts}.tar" unless opts.end_with?('.tar')
|
|
801
745
|
cmd << quote_option('output', File.expand_path(opts))
|
|
@@ -806,9 +750,13 @@ module Squared
|
|
|
806
750
|
else
|
|
807
751
|
cmd << opts << '--'
|
|
808
752
|
end
|
|
809
|
-
cmd.merge(
|
|
753
|
+
cmd.merge(if out.is_a?(Array)
|
|
754
|
+
out.map! { |val| parse.call(val) }
|
|
755
|
+
else
|
|
756
|
+
[parse.call(out)]
|
|
757
|
+
end)
|
|
810
758
|
cmd << args
|
|
811
|
-
print_success if success?(run(cmd
|
|
759
|
+
print_success if success?(run(cmd)) && ctx.start_with?(/(?:network|tag|save)/)
|
|
812
760
|
end
|
|
813
761
|
end
|
|
814
762
|
|
|
@@ -818,7 +766,7 @@ module Squared
|
|
|
818
766
|
bake?(val) ? 1 : 2
|
|
819
767
|
when '.yml', '.yaml'
|
|
820
768
|
if compose?(val)
|
|
821
|
-
|
|
769
|
+
path.children.any? { |file| bake?(file) } ? 1 : 3
|
|
822
770
|
else
|
|
823
771
|
4
|
|
824
772
|
end
|
|
@@ -828,7 +776,7 @@ module Squared
|
|
|
828
776
|
end
|
|
829
777
|
|
|
830
778
|
def contextdir(val = nil)
|
|
831
|
-
val && projectpath?(val) ? shell_quote(
|
|
779
|
+
val && projectpath?(val) ? shell_quote(path + val) : '.'
|
|
832
780
|
end
|
|
833
781
|
|
|
834
782
|
def tagjoin(*args, char: '/')
|
|
@@ -838,9 +786,10 @@ module Squared
|
|
|
838
786
|
|
|
839
787
|
def tagname(val)
|
|
840
788
|
val = val.split(':').map! { |s| charname(s.sub(/^\W+/, '')) }
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
789
|
+
val.join(':').yield_self do |s|
|
|
790
|
+
s = val.first if val.size > 1 && s.size > 128
|
|
791
|
+
s[0..127]
|
|
792
|
+
end
|
|
844
793
|
end
|
|
845
794
|
|
|
846
795
|
def dnsname(val)
|
|
@@ -854,6 +803,14 @@ module Squared
|
|
|
854
803
|
def tagmain
|
|
855
804
|
tag.is_a?(Array) ? tag.first : tag
|
|
856
805
|
end
|
|
806
|
+
|
|
807
|
+
def compose?(file = dockerfile)
|
|
808
|
+
COMPOSEFILE.include?(File.basename(file))
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
def bake?(file = dockerfile)
|
|
812
|
+
BAKEFILE.include?(File.basename(file))
|
|
813
|
+
end
|
|
857
814
|
end
|
|
858
815
|
|
|
859
816
|
Application.implement Docker
|