squared 0.7.4 → 0.7.6

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.
@@ -53,7 +53,7 @@ module Squared
53
53
  end
54
54
  end
55
55
 
56
- def shell_quote(val, option: true, force: true, double: false, preserve: true, override: false)
56
+ def shell_quote(val, option: true, force: true, double: false, preserve: true, pass: false, override: false)
57
57
  val = val.to_s
58
58
  return val if (!force && !val.include?(' ')) || val.empty?
59
59
 
@@ -61,16 +61,16 @@ module Squared
61
61
  pat = /\A(?:-[^=\s-](?:=|\s+)?|(--)?[^=\s-][^=\s]*(?(1)(?:=|\s+)|=))(["']).+\2\z/m
62
62
  return val if val.match?(pat)
63
63
  end
64
- q = ->(s) { s.gsub("'\\\\''", "'") }
65
64
  if val =~ QUOTE_VALUE
66
- return val if $1 == '"' && Rake::Win32.windows? && val.match?(/(?:[#{File::SEPARATOR} ]|\\")/o)
65
+ return val if pass || ($1 == '"' && Rake::Win32.windows? && val.match?(/(?:[#{File::SEPARATOR} ]|\\")/o))
67
66
 
68
67
  base = $2 unless preserve
69
68
  end
69
+ q = -> { (base || val).gsub("'\\\\''", "'") }
70
70
  if double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
71
- "\"#{q.call(base || val).gsub(/(?<!\\)"/, '\\"')}\""
71
+ "\"#{q.call.gsub(/(?<!\\)"/, '\\"')}\""
72
72
  else
73
- base ? val : "'#{q.call(val).gsub("'", "'\\\\''")}'"
73
+ "'#{q.call.gsub("'", "'\\\\''")}'"
74
74
  end
75
75
  end
76
76
 
@@ -124,18 +124,18 @@ module Squared
124
124
  b = []
125
125
  c = []
126
126
  d = []
127
- e = [a, b]
127
+ target = [a, b]
128
128
  j = -1
129
129
  val.shellsplit.each_with_index do |opt, i|
130
130
  if opt == '--'
131
- e = [c, d]
131
+ target = [c, d]
132
132
  elsif opt =~ /\A--?[^=]+(=|\z)/
133
133
  j = $1 == '=' ? -1 : i
134
- e[0] << [opt]
134
+ target[0] << [opt]
135
135
  elsif j >= 0
136
- e[0][j] << opt
136
+ target[0][j] << opt
137
137
  else
138
- e[1] << shell_quote(opt, option: false, force: force)
138
+ target[1] << shell_quote(opt, option: false, force: force)
139
139
  end
140
140
  end
141
141
  ret = [[a, b], [], [c, d]].flat_map do |e, f|
@@ -29,6 +29,7 @@ module Squared
29
29
  module_function
30
30
 
31
31
  def shell(*args, name: :system, **kwargs)
32
+ kwargs.delete(:exception) unless name == :system
32
33
  if RUBY_ENGINE == 'jruby' && Rake::Win32.windows?
33
34
  ex = kwargs[:exception]
34
35
  if (dir = kwargs[:chdir]) && Dir.pwd != dir
@@ -43,7 +44,7 @@ module Squared
43
44
  else
44
45
  return Kernel.send(name, *args, **kwargs)
45
46
  end
46
- raise $?.to_s if !ret && ex && name == :system
47
+ raise $?.to_s if !ret && ex
47
48
 
48
49
  ret
49
50
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.7.4'
4
+ VERSION = '0.7.6'
5
5
  end
@@ -206,7 +206,7 @@ module Squared
206
206
 
207
207
  return self
208
208
  end
209
- raise_error 'method not found'
209
+ raise 'method not found'
210
210
  rescue => e
211
211
  warn log_message(Logger::WARN, e, subject: main, hint: hint || args)
212
212
  end
@@ -226,7 +226,7 @@ module Squared
226
226
  when Symbol
227
227
  @ref = val
228
228
  else
229
- raise_error TypeError, "not a group/ref: #{kind || 'nil'}" if block_given?
229
+ raise TypeError, "not a group/ref: #{kind || 'nil'}" if block_given?
230
230
  end
231
231
  if block_given?
232
232
  instance_eval(&blk)
@@ -934,8 +934,8 @@ module Squared
934
934
  group.each { |val| failed += val.action }
935
935
  puts log_message(Logger::ERROR, *failed, subject: 'failed placement', hint: false), pipe: 2
936
936
  end
937
- level.each_with_index do |grp, i|
938
- title = "Step #{i.succ}#{if sync.include?(grp) && !(grp.size == 1 && series.parallel.include?(grp.first))
937
+ level.each_with_index do |grp, j|
938
+ title = "Step #{j.succ}#{if sync.include?(grp) && !(grp.size == 1 && series.parallel.include?(grp.first))
939
939
  ' (sync)'
940
940
  end}"
941
941
  emphasize(grp, title: title, cols: level.flatten(1).push(title), border: theme[:border],
@@ -950,7 +950,7 @@ module Squared
950
950
  log_console(*args, pipe: kwargs[:pipe] || pipe)
951
951
  end
952
952
 
953
- def script_command(task, val, group, ref, on, &blk)
953
+ def script_command(task, val, group, ref, on = nil, &blk)
954
954
  if block_given?
955
955
  val = Struct::RunData.new(val, blk)
956
956
  elsif !val
@@ -961,7 +961,7 @@ module Squared
961
961
  as_a group, :to_sym
962
962
  else
963
963
  label = :ref
964
- as_a ref, :to_sym
964
+ as_a(ref || :_, :to_sym)
965
965
  end.each do |name|
966
966
  @script[label][name][task] = val
967
967
  @events[label][name][task] = on if on.is_a?(Hash)
@@ -1014,6 +1014,8 @@ module Squared
1014
1014
  nil
1015
1015
  elsif ref && target[:ref].key?(ref)
1016
1016
  target[:ref][ref]
1017
+ else
1018
+ target[:ref][:_]
1017
1019
  end
1018
1020
  end
1019
1021
 
@@ -1027,6 +1029,7 @@ module Squared
1027
1029
  require_relative rb
1028
1030
  break
1029
1031
  end
1032
+ nil
1030
1033
  end
1031
1034
 
1032
1035
  def root?(path, pass: [])
@@ -399,7 +399,7 @@ module Squared
399
399
  end
400
400
 
401
401
  def with(**kwargs, &blk)
402
- @withargs = kwargs.empty? ? nil : kwargs
402
+ @withargs = (kwargs unless kwargs.empty?)
403
403
  if block_given?
404
404
  instance_eval(&blk)
405
405
  @withargs = nil
@@ -862,13 +862,14 @@ module Squared
862
862
  end
863
863
 
864
864
  def run(cmd = @session, var = nil, exception: exception?, sync: true, banner: true, from: nil, chdir: path,
865
- interactive: nil, hint: nil, series: false, timeout: nil, **)
865
+ interactive: nil, hint: nil, series: false, timeout: nil, send: :system, **)
866
866
  unless cmd
867
867
  print_error('no command session started', subject: project, hint: from, pass: true)
868
868
  return
869
869
  end
870
870
  cmd = cmd.target if cmd.is_a?(OptionPartition)
871
871
  if interactive && sync && (!@session || !option('y'))
872
+ print_item(series: true)
872
873
  msg, y, h = case interactive
873
874
  when Array
874
875
  interactive
@@ -901,7 +902,7 @@ module Squared
901
902
  end
902
903
  end
903
904
  args = var.is_a?(Hash) ? [var, cmd] : [cmd]
904
- ret = shell_t(*args, chdir: chdir, exception: exception, timeout: timeout || 0)
905
+ ret = shell_t(*args, name: send, chdir: chdir, exception: exception, timeout: timeout || 0)
905
906
  end
906
907
  rescue Timeout::Error => e
907
908
  print_error(Logger::ERROR, cmd, subject: name, hint: e)
@@ -1350,7 +1351,7 @@ module Squared
1350
1351
  else
1351
1352
  if series?(obj)
1352
1353
  obj.each(&:call)
1353
- elsif obj.is_a?(Array) && obj.any? { |val| !val.is_a?(String) }
1354
+ elsif obj.is_a?(Array) && obj.any? { |val| val.nil? || !val.is_a?(String) }
1354
1355
  build(*obj, **kwargs)
1355
1356
  elsif obj
1356
1357
  run_s(*Array(obj), **kwargs)
@@ -1556,8 +1557,8 @@ module Squared
1556
1557
 
1557
1558
  def session(*cmd, prefix: cmd.first, main: true, path: true, options: true)
1558
1559
  prefix = prefix.to_s.stripext
1559
- if path && (val = shell_bin(prefix))
1560
- cmd[0] = shell_quote(val, force: false)
1560
+ if path && (bin = shell_bin(prefix))
1561
+ cmd[0] = shell_quote(bin, force: false)
1561
1562
  end
1562
1563
  ret = JoinSet.new(cmd)
1563
1564
  if options
@@ -1621,7 +1622,7 @@ module Squared
1621
1622
  args.unshift(*a)
1622
1623
  OptionPartition.uniq!(args, pass) if pass
1623
1624
  end
1624
- kwargs&.update(b) { |_, val| val }
1625
+ kwargs&.update(b) { |_, obj| obj }
1625
1626
  nil
1626
1627
  end
1627
1628
 
@@ -1667,8 +1668,8 @@ module Squared
1667
1668
  end
1668
1669
 
1669
1670
  def write_lines(data, grep: [], prefix: nil, sub: nil, banner: nil, loglevel: nil, pass: false, first: false)
1670
- grep = grep.empty? ? nil : matchmap(grep, prefix)
1671
- sub = stdin? ? nil : as_a(sub)
1671
+ grep = (matchmap(grep, prefix) unless grep.empty?)
1672
+ sub = (as_a(sub) unless stdin?)
1672
1673
  ret = 0
1673
1674
  lines = data.each_with_object([]) do |line, out|
1674
1675
  next if grep&.none? { |pat| pat.match?(line) }
@@ -1789,7 +1790,7 @@ module Squared
1789
1790
  workspace.format_desc([@desc, action, flag].compact, opts, **kwargs)
1790
1791
  end
1791
1792
 
1792
- def format_banner(cmd, banner: true, hint: nil, strip: nil, quote: false)
1793
+ def format_banner(cmd, banner: true, hint: nil, strip: nil, quote: false, command: true)
1793
1794
  return unless banner && banner?
1794
1795
 
1795
1796
  if (data = workspace.banner_get(*@ref, group: group))
@@ -1802,15 +1803,17 @@ module Squared
1802
1803
  if verbose
1803
1804
  out = []
1804
1805
  if data.command
1805
- if cmd =~ /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+))( |\z)/
1806
- arg = $3 || $2 || $1
1807
- cmd = cmd.sub(arg, data.command == 0 ? arg.stripext : arg.stripext.upcase)
1808
- end
1809
- if strip || (strip.nil? && data.order.include?(:path))
1810
- cmd = cmd.gsub(/(?:#{s = Regexp.escape(File.join(path, ''))}?(?=["'])|#{s})/, '')
1811
- .gsub(/(?: -[^ ])? (?:""|'')/, '')
1806
+ if command
1807
+ if cmd =~ /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+))( |\z)/
1808
+ arg = $3 || $2 || $1
1809
+ cmd = cmd.sub(arg, data.command == 0 ? arg.stripext : arg.stripext.upcase)
1810
+ end
1811
+ if strip || (strip.nil? && data.order.include?(:path))
1812
+ cmd = cmd.gsub(/(?:#{s = Regexp.escape(File.join(path, ''))}?(?=["'])|#{s})/, '')
1813
+ .gsub(/(?: -[^ ])? (?:""|'')/, '')
1814
+ end
1815
+ cmd.gsub!(/(?<= )(["'])([\w.-]+)\1(?= |\z)/, '\2') unless quote
1812
1816
  end
1813
- cmd.gsub!(/(?<= )(["'])([\w.-]+)\1(?= |\z)/, '\2') unless quote
1814
1817
  out << cmd.subhint(hint)
1815
1818
  end
1816
1819
  data.order.each do |val|
@@ -2129,7 +2132,7 @@ module Squared
2129
2132
  force = false
2130
2133
  end
2131
2134
  val = readline(val, force: force)
2132
- ret << (val.empty? ? nil : val)
2135
+ ret << (val unless val.empty?)
2133
2136
  end
2134
2137
  end
2135
2138
  printsucc unless series
@@ -2188,7 +2191,7 @@ module Squared
2188
2191
  files = files.select { |val| projectpath?(val) }.tap do |list|
2189
2192
  next if pass || files.size == list.size
2190
2193
 
2191
- raise_error 'pathspec not within worktree'
2194
+ raise 'pathspec not within worktree'
2192
2195
  end
2193
2196
  end
2194
2197
  files.map do |val|
@@ -2392,7 +2395,7 @@ module Squared
2392
2395
  return if from == false
2393
2396
 
2394
2397
  require 'timeout'
2395
- unless (path.to_s == Dir.pwd || pass == true) && (workspace.mri? || !workspace.windows?)
2398
+ unless (path.to_s == Dir.pwd || pass) && (workspace.mri? || !workspace.windows?)
2396
2399
  pwd = Dir.pwd
2397
2400
  Dir.chdir(path)
2398
2401
  end
@@ -2715,6 +2718,10 @@ module Squared
2715
2718
  level.empty? ? ex != false && ex != Logger::INFO : ex.is_a?(Numeric) && level.include?(ex)
2716
2719
  end
2717
2720
 
2721
+ def strict?
2722
+ (ARG[:STRICT] || exception?(Logger::FATAL)) && env('STRICT', notequals: '0')
2723
+ end
2724
+
2718
2725
  def serve?
2719
2726
  false
2720
2727
  end
@@ -20,7 +20,7 @@ module Squared
20
20
  sbom=q].freeze
21
21
  }.freeze,
22
22
  compose: {
23
- common: %w[all-resources ansi|b compatibility dry-run env-file=p f|file=p parallel=n profile=b progress=b
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,
@@ -399,28 +399,28 @@ module Squared
399
399
  end
400
400
 
401
401
  def buildx(flag, opts = [], tag: nil, context: nil, from: nil)
402
+ if flag == :bake && context&.match?(%r{^["']?(https?|git)://}i)
403
+ shared = data[:shared].dup.push('f|file=q')
404
+ shared.delete('f|file=p')
405
+ end
402
406
  cmd, opts = docker_session('buildx', opts: opts)
403
407
  data = OPT_DOCKER[:buildx]
404
- op = OptionPartition.new(opts, data[:common], cmd, project: self)
408
+ op = OptionPartition.new(opts, data[:common], cmd, project: self, strict: strict?)
405
409
  op.append(flag, quote: false)
406
- .parse(data[flag == :bake ? :bake : :build] + data[:shared])
410
+ .parse(data[flag == :bake ? :bake : :build] + (shared || data[:shared]))
407
411
  case flag
408
412
  when :build, :context
409
413
  append_tag(tag || option('tag', ignore: false) || self.tag)
410
- append_context context
414
+ if shared
415
+ op.add_quote(context, preserve: false)
416
+ else
417
+ append_context context
418
+ end
411
419
  when :bake
412
420
  append_file(0, index: 3) unless from || op.arg?('f', 'file') || !anypath?(*COMPOSEFILE)
413
421
  unless op.empty?
414
- args = op.dup
415
- op.reset
416
- if Dir.exist?(args.last)
417
- if projectpath?(val = args.pop)
418
- context = val
419
- else
420
- op.push(val)
421
- end
422
- end
423
- op.append(args, escape: true, strip: /^:/)
422
+ context = op.pop if Dir.exist?(op.last) && projectpath?(op.last)
423
+ op.append(escape: true, strip: /^:/, clear: true)
424
424
  contextdir context if context
425
425
  end
426
426
  end
@@ -442,7 +442,7 @@ module Squared
442
442
  docker_session('compose', command, '--', *service)
443
443
  else
444
444
  cmd, opts = docker_session('compose', opts: opts)
445
- op = OptionPartition.new(opts, OPT_DOCKER[:compose][:common], cmd, project: self)
445
+ op = OptionPartition.new(opts, OPT_DOCKER[:compose][:common], cmd, project: self, strict: strict?)
446
446
  append_file(filetype, force: flag == :publish) unless op.arg?('f', 'file')
447
447
  op << flag
448
448
  op.parse(OPT_DOCKER[:compose].fetch(flag, []))
@@ -479,7 +479,7 @@ module Squared
479
479
  list = data.fetch(flag, [])
480
480
  list += data[:create] if (rc = flag == :run)
481
481
  list += data[:update] if rc ||= flag == :create
482
- op = OptionPartition.new(opts, list, cmd, project: self, args: rc || flag == :exec)
482
+ op = OptionPartition.new(opts, list, cmd, project: self, strict: strict?, args: rc || flag == :exec)
483
483
  from = symjoin 'container', flag
484
484
  case flag
485
485
  when :run, :create, :exec
@@ -562,7 +562,7 @@ module Squared
562
562
 
563
563
  def image(flag, opts = [], sync: true, id: nil, registry: nil, filter: nil)
564
564
  cmd, opts = docker_session('image', flag, opts: opts)
565
- op = OptionPartition.new(opts, OPT_DOCKER[:image].fetch(flag, []), cmd, project: self)
565
+ op = OptionPartition.new(opts, OPT_DOCKER[:image].fetch(flag, []), cmd, project: self, strict: strict?)
566
566
  exception = exception?
567
567
  banner = true
568
568
  from = symjoin 'image', flag
@@ -645,7 +645,7 @@ module Squared
645
645
 
646
646
  def network(flag, opts = [], target: nil)
647
647
  cmd, opts = docker_session('network', flag, opts: opts)
648
- op = OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, project: self)
648
+ op = OptionPartition.new(opts, OPT_DOCKER[:network].fetch(flag, []), cmd, project: self, strict: strict?)
649
649
  .clear
650
650
  from = symjoin 'network', flag
651
651
  if flag == :create
@@ -712,7 +712,7 @@ module Squared
712
712
  def docker_session(*cmd, opts: nil)
713
713
  return session('docker', *cmd) unless opts
714
714
 
715
- op = OptionPartition.new(opts, OPT_DOCKER[:common], project: self)
715
+ op = OptionPartition.new(opts, OPT_DOCKER[:common], project: self, strict: strict?)
716
716
  [session('docker', *op.to_a, *cmd), op.extras]
717
717
  end
718
718
 
@@ -898,11 +898,11 @@ module Squared
898
898
  when :service
899
899
  ['Choose a service',
900
900
  'compose ps -a ' \
901
- "--format='table {{.Service}}\t{{.Name}}\t{{.Image}}\t{{.Command}}\t{{.Status}}\t{{.Ports}}'"]
901
+ '--format="table {{.Service}}\t{{.Name}}\t{{.Image}}\t{{.Command}}\t{{.Status}}\t{{.Ports}}"']
902
902
  else
903
903
  ['Choose an image',
904
904
  'images -a ' \
905
- "--format='table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.CreatedSince}}\t{{.Size}}'"]
905
+ '--format="table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.CreatedSince}}\t{{.Size}}"']
906
906
  end
907
907
  lines = `#{docker_output(cmd)}`.lines
908
908
  if lines.size <= 1