squared 0.4.6 → 0.4.8

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.
@@ -125,7 +125,7 @@ module Squared
125
125
  return unless ref?(Docker.ref)
126
126
 
127
127
  namespace name do
128
- @@tasks[Docker.ref].each do |action, flags|
128
+ Docker.subtasks do |action, flags|
129
129
  next if @pass.include?(action)
130
130
 
131
131
  namespace action do
@@ -151,31 +151,38 @@ module Squared
151
151
  when :build, :up
152
152
  format_desc action, flag, 'opts*,service*'
153
153
  task flag do |_, args|
154
- composex flag, args.to_a
154
+ compose! flag, args.to_a
155
155
  end
156
156
  when :exec, :run
157
157
  format_desc action, flag, "service,command#{flag == :exec ? '' : '?'},args*,opts*"
158
158
  task flag, [:service] do |_, args|
159
159
  service = param_guard(action, flag, args: args, key: :service)
160
- composex(flag, args.extras, service: service)
160
+ compose!(flag, args.extras, service: service)
161
161
  end
162
162
  end
163
163
  when 'container'
164
164
  case flag
165
165
  when :exec, :commit
166
- format_desc(action, flag, 'id/name,opts*', after: flag == :exec ? 'args+' : 'tag?')
166
+ format_desc(action, flag, flag == :exec ? 'id/name?,opts*,args+' : 'id/name,tag?,opts*')
167
167
  task flag, [:id] do |_, args|
168
- id = param_guard(action, flag, args: args, key: :id)
169
- container(flag, args.extras, id: id)
168
+ if flag == :exec && !args.id
169
+ choice_command flag
170
+ else
171
+ id = param_guard(action, flag, args: args, key: :id)
172
+ container(flag, args.extras, id: id)
173
+ end
170
174
  end
171
175
  when :run
172
- format_desc action, flag, 'image,opts*,args*'
176
+ format_desc action, flag, 'image?,opts*,args*'
173
177
  task flag, [:image] do |_, args|
174
- image = param_guard(action, flag, args: args, key: :image)
175
- container(flag, args.extras, id: image)
178
+ if args.image
179
+ container(flag, args.extras, id: args.image)
180
+ else
181
+ choice_command flag
182
+ end
176
183
  end
177
184
  else
178
- format_desc(action, flag, 'opts*', after: "id/name#{flag == :update ? '+' : '*'}")
185
+ format_desc(action, flag, 'opts*,id/name', after: flag == :update ? '+' : '*')
179
186
  task flag do |_, args|
180
187
  container flag, args.to_a
181
188
  end
@@ -188,7 +195,7 @@ module Squared
188
195
  tag = param_guard(action, flag, args: args, key: :tag)
189
196
  image(flag, args.extras, id: tag)
190
197
  end
191
- else
198
+ when :list, :rm
192
199
  format_desc(action, flag, flag == :rm ? 'id*,opts*' : 'opts*,args*')
193
200
  task flag do |_, args|
194
201
  image flag, args.to_a
@@ -197,8 +204,11 @@ module Squared
197
204
  when 'network'
198
205
  format_desc action, flag, 'target,opts*'
199
206
  task flag, [:target] do |_, args|
200
- target = param_guard(action, flag, args: args, key: :target)
201
- network(flag, args.extras, target: target)
207
+ if (target = args.target)
208
+ network(flag, args.extras, target: target)
209
+ else
210
+ choice_command flag
211
+ end
202
212
  end
203
213
  end
204
214
  end
@@ -251,13 +261,13 @@ module Squared
251
261
  when :build
252
262
  case @secrets
253
263
  when String
254
- quote_option('secret', @secrets, double: true)
264
+ ret << quote_option('secret', @secrets, double: true)
255
265
  when Hash
256
266
  append = lambda do |type|
257
267
  as_a(@secrets[type]).each { |arg| ret << quote_option('secret', "type=#{type},#{arg}", double: true) }
258
268
  end
259
- append.(:file)
260
- append.(:env)
269
+ append.call(:file)
270
+ append.call(:env)
261
271
  else
262
272
  as_a(@secrets).each { |arg| ret << quote_option('secret', arg) }
263
273
  end
@@ -278,45 +288,44 @@ module Squared
278
288
 
279
289
  def buildx(flag, opts = [], tag: nil, context: nil)
280
290
  cmd, opts = docker_session('buildx', opts: opts)
281
- opts = option_sanitize(opts, OPT_DOCKER[:buildx][:common]).first
282
- cmd << flag
283
- list = OPT_DOCKER[:buildx][flag == :bake ? :bake : :build] + OPT_DOCKER[:buildx][:shared]
284
- out = option_sanitize(opts, list).first
291
+ op = OptionPartition.new(opts, OPT_DOCKER[:buildx][:common], cmd, project: self)
292
+ op << flag
293
+ op.parse(OPT_DOCKER[:buildx][flag == :bake ? :bake : :build] + OPT_DOCKER[:buildx][:shared])
285
294
  case flag
286
295
  when :build, :context
287
296
  append_tag(tag || option('tag', ignore: false) || @tag)
288
297
  append_context context
289
298
  when :bake
290
- unless out.empty?
291
- args = out.dup
292
- out.clear
299
+ unless op.empty?
300
+ args = op.dup
301
+ op.extras.clear
293
302
  if Dir.exist?(args.last)
294
303
  if projectpath?(val = args.pop)
295
304
  context = val
296
305
  else
297
- out << val
306
+ op.extras << val
298
307
  end
299
308
  end
300
- append_value(args, escape: true)
309
+ op.append(args, escape: true)
301
310
  contextdir(context) if context
302
311
  end
303
312
  end
304
- option_clear(out, pass: false)
313
+ op.clear(pass: false)
305
314
  run(from: :"buildx:#{flag}")
306
315
  end
307
316
 
308
- def composex(flag, opts = [], service: nil)
317
+ def compose!(flag, opts = [], service: nil)
309
318
  cmd, opts = docker_session('compose', opts: opts)
310
- opts = option_sanitize(opts, OPT_DOCKER[:compose][:common]).first
311
- append_file filetype unless session_arg?('f', 'file')
312
- cmd << flag
313
- out = option_sanitize(opts, OPT_DOCKER[:compose][flag]).first
319
+ op = OptionPartition.new(opts, OPT_DOCKER[:compose][:common], cmd, project: self)
320
+ append_file filetype unless op.arg?('f', 'file')
321
+ op << flag
322
+ op.parse(OPT_DOCKER[:compose][flag])
314
323
  from = :"compose:#{flag}"
315
324
  case flag
316
325
  when :build, :up
317
- append_value(out, escape: true)
326
+ op.append(escape: true)
318
327
  when :exec, :run
319
- append_command(flag, service, out, from: from)
328
+ append_command(flag, service, op.extras, from: from)
320
329
  end
321
330
  run(from: from)
322
331
  end
@@ -324,12 +333,12 @@ module Squared
324
333
  def container(flag, opts = [], id: nil)
325
334
  cmd, opts = docker_session('container', flag, opts: opts)
326
335
  list = OPT_DOCKER[:container].fetch(flag, [])
327
- list += OPT_DOCKER[:container][:update] if flag == :run
328
- out = option_sanitize(opts, list, args: flag == :run || flag == :exec).first
336
+ list.concat(OPT_DOCKER[:container][:update]) if flag == :run
337
+ op = OptionPartition.new(opts, list, cmd, project: self, args: flag == :run || flag == :exec)
329
338
  from = :"container:#{flag}"
330
339
  case flag
331
340
  when :run, :exec
332
- if flag == :run && !session_arg?('mount')
341
+ if flag == :run && !op.arg?('mount')
333
342
  run = VAL_DOCKER[:run]
334
343
  both = run[:bind] + run[:tmpfs]
335
344
  diff = run[:bind].reject { |val| run[:tmpfs].include?(val) }
@@ -361,14 +370,14 @@ module Squared
361
370
  cmd << "--mount type=#{tmpfs ? 'tmpfs' : 'bind'},#{args.join(',')}"
362
371
  end
363
372
  end
364
- append_command(flag, id.to_s.empty? ? tagmain : id, out, from: from)
373
+ append_command(flag, id.to_s.empty? ? tagmain : id, op.extras, from: from)
365
374
  when :update
366
- raise_error('missing container', hint: from) if out.empty?
367
- append_value(out, escape: true)
375
+ raise_error('missing container', hint: from) if op.empty?
376
+ op.append(escape: true)
368
377
  when :commit
369
- latest = out.shift || tagmain
378
+ latest = op.shift || tagmain
370
379
  cmd << id << latest
371
- raise_error("unknown args: #{out.join(', ')}", hint: from) unless out.empty?
380
+ raise_error("unknown args: #{op.join(', ')}", hint: from) unless op.empty?
372
381
  return unless confirm_command(cmd.to_s, title: from, target: id, as: latest)
373
382
 
374
383
  registry = option('registry') || @registry
@@ -386,7 +395,7 @@ module Squared
386
395
  opts << '--quiet' unless verbose
387
396
  return image(:push, opts, id: latest, registry: registry)
388
397
  else
389
- if out.empty?
398
+ if op.empty?
390
399
  status = []
391
400
  no = true
392
401
  case flag
@@ -411,13 +420,13 @@ module Squared
411
420
  when :rm
412
421
  status = %w[created exited dead]
413
422
  end
414
- ps = docker_output('ps -a', *status.map! { |s| "--filter='status=#{s}'" })
423
+ ps = docker_output('ps -a', *status.map { |s| "--filter='status=#{s}'" })
415
424
  list_image(flag, ps, no: no, hint: "status: #{status.join(', ')}", from: from) do |img|
416
425
  run(cmd.temp(img), from: from)
417
426
  end
418
427
  return
419
428
  else
420
- append_value(out, escape: true)
429
+ op.append(escape: true)
421
430
  end
422
431
  end
423
432
  run(from: from)
@@ -425,11 +434,11 @@ module Squared
425
434
 
426
435
  def image(flag, opts = [], sync: true, id: nil, registry: nil)
427
436
  cmd, opts = docker_session('image', flag, opts: opts)
428
- out = option_sanitize(opts, OPT_DOCKER[:image][flag]).first
437
+ op = OptionPartition.new(opts, OPT_DOCKER[:image][flag], cmd, project: self)
429
438
  from = :"image:#{flag}"
430
439
  case flag
431
440
  when :list
432
- if opts.size == out.size
441
+ if opts.size == op.size
433
442
  index = 0
434
443
  name = nil
435
444
  opts.reverse_each { |opt| break opts.delete(opt) if (name = opt[/^name=["']?(.+?)["']?$/, 1]) }
@@ -443,28 +452,29 @@ module Squared
443
452
  end
444
453
  return
445
454
  else
446
- option_clear out
455
+ op.clear
447
456
  end
448
457
  when :rm
449
458
  if id
450
- cmd << id
451
- elsif !out.empty?
452
- out.each { |val| run(cmd.temp(val), sync: sync, from: from) }
453
- return
459
+ op << id
454
460
  else
455
- list_image(flag, docker_output('image ls -a'), from: from) do |val|
456
- image(:rm, opts, sync: sync, id: val)
461
+ if op.empty?
462
+ list_image(flag, docker_output('image ls -a'), from: from) do |val|
463
+ image(:rm, opts, sync: sync, id: val)
464
+ end
465
+ else
466
+ op.each { |val| run(cmd.temp(val), sync: sync, from: from) }
457
467
  end
458
468
  return
459
469
  end
460
470
  when :push
461
471
  id ||= option('tag', ignore: false) || tagmain
462
- registry ||= out.shift || option('registry') || @registry
463
- raise_error(id ? "unknown args: #{out.join(', ')}" : 'no id/tag given', hint: from) unless id && out.empty?
472
+ registry ||= op.shift || option('registry') || @registry
473
+ raise_error(id ? "unknown args: #{op.join(', ')}" : 'no id/tag given', hint: from) unless id && op.empty?
464
474
  raise_error('username/registry not provided', hint: from) unless registry
465
475
  registry.chomp!('/')
466
476
  uri = shell_quote("#{registry}/#{id}")
467
- cmd << uri
477
+ op << uri
468
478
  img = docker_output 'image', 'tag', id, uri
469
479
  return unless confirm_command(img.to_s, cmd.to_s, target: id, as: registry, title: from)
470
480
 
@@ -475,7 +485,8 @@ module Squared
475
485
 
476
486
  def network(flag, opts = [], target: nil)
477
487
  cmd, opts = docker_session('network', flag, opts: opts)
478
- option_sanitize(opts, OPT_DOCKER[:network][flag]).first
488
+ op = OptionPartition.new(opts, OPT_DOCKER[:network][flag], cmd, project: self)
489
+ op.clear
479
490
  from = :"network:#{flag}"
480
491
  list_image(flag, docker_output('ps -a'), from: from) do |img|
481
492
  puts 'Success' if run(cmd.temp(target, img), from: from) == true && stdout? && banner?
@@ -510,10 +521,9 @@ module Squared
510
521
  def docker_session(*cmd, opts: nil)
511
522
  return session('docker', *cmd) unless opts
512
523
 
513
- out = []
514
- opts = option_sanitize(opts, OPT_DOCKER[:common], target: out).first
515
- ret = session('docker', *out, *cmd)
516
- [ret, opts]
524
+ op = OptionPartition.new(opts, OPT_DOCKER[:common], project: self)
525
+ ret = session('docker', *op.to_a, *cmd)
526
+ [ret, op.extras]
517
527
  end
518
528
 
519
529
  def docker_output(*cmd, **kwargs)
@@ -521,9 +531,12 @@ module Squared
521
531
  end
522
532
 
523
533
  def append_command(flag, val, list, target: @session, from: nil)
534
+ if (args = env('DOCKER_ARGS'))
535
+ list << args
536
+ end
524
537
  case flag
525
538
  when :run
526
- unless session_arg?('name')
539
+ unless session_arg?('name', target: target)
527
540
  require 'random/formatter'
528
541
  target << basic_option('name', dnsname("#{name}_#{Random.new.alphanumeric(6)}"))
529
542
  end
@@ -531,24 +544,29 @@ module Squared
531
544
  raise_error('no command args', hint: from) if list.empty?
532
545
  end
533
546
  target << val << list.shift
534
- target << shell_quote(list.join(' && '), double: true, option: false) unless list.empty?
547
+ target << list.join(' && ') unless list.empty?
535
548
  end
536
549
 
537
550
  def append_file(type, target: @session)
538
551
  return unless type == 2 || type == 4 || @file.is_a?(Array)
539
552
 
540
- target.merge(as_a(@file).map { |val| quote_option('file', basepath(val)) })
553
+ files = as_a(@file).map { |val| quote_option('file', basepath(val)) }
554
+ if target.is_a?(Set)
555
+ target.merge(files)
556
+ else
557
+ target.concat(files)
558
+ end
541
559
  end
542
560
 
543
561
  def append_context(ctx = nil, target: @session)
544
- if @file.is_a?(String) && !session_arg?('f', 'file') && !bake?(dockerfile) && !compose?(dockerfile)
562
+ if @file.is_a?(String) && !session_arg?('f', 'file', target: target) && !bake? && !compose?
545
563
  target << quote_option('file', dockerfile)
546
564
  end
547
565
  target << contextdir(ctx || context)
548
566
  end
549
567
 
550
568
  def append_tag(val, target: @session)
551
- ver = option('version', ignore: false)
569
+ ver = option('version', target: target, ignore: false)
552
570
  list = case val
553
571
  when String
554
572
  val.split(',')
@@ -563,7 +581,7 @@ module Squared
563
581
  end
564
582
  end
565
583
 
566
- def list_image(flag, cmd, hint: nil, from: nil, no: true, &blk)
584
+ def list_image(flag, cmd, hint: nil, from: nil, no: true)
567
585
  pwd_set do
568
586
  found = false
569
587
  index = 0
@@ -580,14 +598,14 @@ module Squared
580
598
  id
581
599
  end)
582
600
  ee = data['Image'] || rt || aa
583
- next unless ee.match?(pat) || aa.match?(pat)
601
+ next unless option('all') || ee.match?(pat) || aa.match?(pat)
584
602
 
585
603
  bb = index.succ.to_s
586
604
  cc = bb.size + 1
587
605
  a = sub_style(ee, styles: theme[:inline])
588
606
  b = "Execute #{sub_style(flag, styles: theme[:active])} on #{a}#{ee == id ? '' : " (#{id})"}"
589
607
  c, d = no ? ['y/N', 'N'] : ['Y/n', 'Y']
590
- e = time_format(time_offset(data['CreatedAt']), pass: ['ms'])
608
+ e = time_format(time_since(data['CreatedAt']), pass: ['ms'])
591
609
  f = sub_style(ARG[:BORDER][0], styles: theme[:inline])
592
610
  g = ' ' * (cc + 1)
593
611
  h = "#{sub_style(bb.rjust(cc), styles: theme[:current])} #{f} "
@@ -612,7 +630,7 @@ module Squared
612
630
  next unless confirm("#{h + b}? [#{c}] ", d, timeout: 60)
613
631
 
614
632
  puts if @@print_order == 0
615
- blk.call id
633
+ yield id
616
634
  end
617
635
  puts log_message(Logger::INFO, 'none detected', subject: "#{name}:#{from}", hint: hint) unless found
618
636
  end
@@ -640,6 +658,35 @@ module Squared
640
658
  confirm("#{a} #{b}#{c ? " as #{c}" : ''}? [y/N] ", 'N', timeout: 60)
641
659
  end
642
660
 
661
+ def choice_command(flag)
662
+ msg, cmd, index = case flag
663
+ when :run
664
+ ['Choose an image', 'images -a', 2]
665
+ when :exec
666
+ ['Choose a container', 'ps -a', 0]
667
+ else
668
+ ['Choose a network', 'network ls', 0]
669
+ end
670
+ lines = `#{docker_output(cmd)}`.lines
671
+ header = lines.shift
672
+ if lines.empty?
673
+ puts log_message(Logger::INFO, 'none found', subject: name, hint: "docker #{cmd}")
674
+ else
675
+ puts " # #{header}"
676
+ case flag
677
+ when :run, :exec
678
+ values = [['Options', flag == :run], ['Command arguments', flag == :exec]]
679
+ cmd = flag.to_s
680
+ else
681
+ values = [['Options', false], ['Container', true]]
682
+ cmd = "network #{flag}"
683
+ end
684
+ out, opts, args = choice_index(msg, lines, values: values)
685
+ ret = run docker_output(cmd, opts, '--', out.split(/\s+/)[index], args)
686
+ puts 'Success' if ret && cmd.start_with?('network')
687
+ end
688
+ end
689
+
643
690
  def filetype(val = dockerfile)
644
691
  case File.extname(val)
645
692
  when '.hcl', '.json'
@@ -678,11 +725,11 @@ module Squared
678
725
  tag.is_a?(Array) ? tag.first : tag
679
726
  end
680
727
 
681
- def compose?(file)
728
+ def compose?(file = dockerfile)
682
729
  COMPOSEFILE.include?(File.basename(file))
683
730
  end
684
731
 
685
- def bake?(file)
732
+ def bake?(file = dockerfile)
686
733
  BAKEFILE.include?(File.basename(file))
687
734
  end
688
735
  end