squared 0.7.10 → 0.7.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf477ce6ea561419bddfea1572f95762934d01c5d5e94bd3cd65e027a96bdcc8
4
- data.tar.gz: ffbdcaea4e1a2dc293b75fe99c8e121baa444c8784175aa6117134921fb59e46
3
+ metadata.gz: a1f82d48ab79c1dc869f6c34dbef07e57c7b1bd9cc0ce8b54582d2029d5e9889
4
+ data.tar.gz: 55526a1592b3b6ef2aec992288fd74b7772837abc733d4eb6dc69f9e7a208cc6
5
5
  SHA512:
6
- metadata.gz: e86f20679d0f906ed3ae080963014c88f2b747dd5570d3e8bf0037f7f0d4670ce257dc6720b13d94fc8f044f16e89a535f09634f7cee8bc5d7061a2f8d2b7485
7
- data.tar.gz: 41c08e924735c9626889f6075a3eb3b5a00bf8f9e9b487ccf29f9de161a3b93702ee1658ea9a73d323bceea31671ea08ab74f58ad83151a5e5bd2929351c6c60
6
+ metadata.gz: 4b60c4bd1db9d601b87ae2e686c3d7ec2190cf766307186a682e10f0e200e5e5280196a7eb55d3c9821707189e9953b6ba1a76c2757ad1f10fec3c96e0d88a83
7
+ data.tar.gz: b4527aff9694bf17460b65f0395d30147faaf5ccaee9042ac47e5d81d5f988470ff8e878e20f6a8dc22c39d7bcc166e15e953443a0785d46a71c5cb2aece8871
data/CHANGELOG.md CHANGED
@@ -1,5 +1,76 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.12] - 2026-09-23
4
+
5
+ ### Fixed
6
+
7
+ - See `0.4.42`.
8
+
9
+ ## [0.6.19]
10
+
11
+ ### Fixed
12
+
13
+ - See `0.4.42`.
14
+
15
+ ## [0.5.27]
16
+
17
+ ### Fixed
18
+
19
+ - See `0.4.42`.
20
+
21
+ ## [0.4.42]
22
+
23
+ ### Fixed
24
+
25
+ - OptionPartition did not strip pre-existing quotes when parsing options.
26
+ - Node command outdated did not strip styling from semver in package.json.
27
+ - Git command show did not recognize object names.
28
+ - Docker destination mounts that are not absolute are treated as errors.
29
+ - Docker source mounts for any named volumes or images were inoperable.
30
+
31
+ ## [0.7.11] - 2026-09-04
32
+
33
+ ### Added
34
+
35
+ - Node command package action [approve|deny] is interactive.
36
+
37
+ ### Fixed
38
+
39
+ - Docker container commands [run|exec] did not sanitize input prompt.
40
+
41
+ ## [0.6.18]
42
+
43
+ ### Added
44
+
45
+ - Docker command bake action buildx with first arg "-" inherits base args.
46
+
47
+ ### Fixed
48
+
49
+ - Git action grep did not recognize format and max-count.
50
+
51
+ ## [0.5.26]
52
+
53
+ ### Fixed
54
+
55
+ - Node command nvm did not quote executable path.
56
+
57
+ ## [0.4.41]
58
+
59
+ ### Added
60
+
61
+ - Common base argument SUCCESS for command confirmation was created.
62
+
63
+ ### Changed
64
+
65
+ - Program options prefer using quotes instead of escape.
66
+ - Docker container run arguments with a leading dash are concatenated.
67
+
68
+ ### Fixed
69
+
70
+ - Common prompt method choice did not grep list items.
71
+ - OptionPartition static method strip did not parse flags with dashes.
72
+ - Project base method choice_index did not support multiple selections.
73
+
3
74
  ## [0.7.10] - 2026-08-06
4
75
 
5
76
  ### Fixed
@@ -1947,6 +2018,8 @@
1947
2018
 
1948
2019
  - Changelog was created.
1949
2020
 
2021
+ [0.7.12]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.12
2022
+ [0.7.11]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.11
1950
2023
  [0.7.10]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.10
1951
2024
  [0.7.9]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.9
1952
2025
  [0.7.8]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.8
@@ -1958,6 +2031,8 @@
1958
2031
  [0.7.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.2
1959
2032
  [0.7.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.1
1960
2033
  [0.7.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.0
2034
+ [0.6.19]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.19
2035
+ [0.6.18]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.18
1961
2036
  [0.6.17]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.17
1962
2037
  [0.6.16]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.16
1963
2038
  [0.6.15]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.15
@@ -1976,6 +2051,8 @@
1976
2051
  [0.6.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.2
1977
2052
  [0.6.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.1
1978
2053
  [0.6.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.0
2054
+ [0.5.27]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.27
2055
+ [0.5.26]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.26
1979
2056
  [0.5.25]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.25
1980
2057
  [0.5.24]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.24
1981
2058
  [0.5.23]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.23
@@ -2002,6 +2079,8 @@
2002
2079
  [0.5.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.2-ruby
2003
2080
  [0.5.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.1-ruby
2004
2081
  [0.5.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.0-ruby
2082
+ [0.4.42]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.42
2083
+ [0.4.41]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.41
2005
2084
  [0.4.40]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.40
2006
2085
  [0.4.39]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.39
2007
2086
  [0.4.38]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.38
@@ -15,6 +15,7 @@ module Squared
15
15
  CHOICE: 25,
16
16
  QUOTE: "'",
17
17
  SPACE: ' => ',
18
+ SUCCESS: 'Success',
18
19
  GRAPH: %w[| - | \\ -].freeze,
19
20
  BORDER: %w[| - - - - - | | - -].freeze,
20
21
  VIEW: 'view',
@@ -56,10 +56,11 @@ module Squared
56
56
  def choice(msg, list = nil, min: 1, max: 1, multiple: false, index: false, grep: nil, border: nil, auto: true,
57
57
  force: true, attempts: 3, timeout: 0)
58
58
  require 'timeout'
59
+ multiple = Array(multiple) if multiple.is_a?(::Numeric)
59
60
  if list
60
61
  grep &&= Array(grep).map { |val| Regexp.new(val) }
61
62
  items = list.each_with_object([]) do |val, out|
62
- next if grep&.none? { |pat| pat.match?(line) }
63
+ next if grep&.none? { |pat| pat.match?(val) }
63
64
 
64
65
  out << val.to_s.chomp
65
66
  puts '%2d. %s' % [out.size, val]
@@ -76,7 +77,7 @@ module Squared
76
77
  puts print_footer(border: border)
77
78
  end
78
79
  msg = "#{msg + (force ? ':' : '?')} [#{min}-#{max}#{if (n = multiple)
79
- "|,#{n.is_a?(::Numeric) ? "{#{n}}" : '*'}"
80
+ "|,#{n.is_a?(::Array) ? "{#{n.join(',')}}" : '*'}"
80
81
  end}] "
81
82
  end
82
83
  end
@@ -105,7 +106,7 @@ module Squared
105
106
  unless k.include?(nil)
106
107
  k.uniq!
107
108
  k.sort!
108
- unless multiple.is_a?(::Numeric) && multiple != k.size
109
+ unless multiple.is_a?(::Array) && !multiple.include?(k.size)
109
110
  return index || !items ? k : k.map { |i| items[i.pred] }
110
111
  end
111
112
  end
@@ -140,7 +140,7 @@ module Squared
140
140
  end
141
141
 
142
142
  def env_key(*val)
143
- val.join('_').gsub(/\W+/, '_').upcase
143
+ val.join('_').sub(/\A\d+\W*/, '__').gsub(/\W+/, '_').upcase
144
144
  end
145
145
 
146
146
  def env_bool(key, default = false, index: false, **kwargs)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.7.10'
4
+ VERSION = '0.7.12'
5
5
  end
@@ -1703,7 +1703,7 @@ module Squared
1703
1703
  end
1704
1704
 
1705
1705
  def print_success
1706
- puts 'Success'
1706
+ puts ARG[:SUCCESS]
1707
1707
  end
1708
1708
 
1709
1709
  def print_error(*args, loglevel: Logger::WARN, **kwargs)
@@ -2121,7 +2121,10 @@ module Squared
2121
2121
  if accept
2122
2122
  hint = Array(ret).map { |val| sub_style(val.to_s, theme[:inline]) }.join(', ')
2123
2123
  accept = Array(accept).map { |val| Array(val) }
2124
- ret = Array(ret) if accept.any? { |val| val[1] == true }
2124
+ if accept.any? { |val| val[1] == true }
2125
+ ret = [ret]
2126
+ multiple = -1
2127
+ end
2125
2128
  begin
2126
2129
  item = accept.shift
2127
2130
  c = confirm("#{item[0]}#{" [#{hint}]" if hint}", item[2] ? 'Y' : 'N')
@@ -2134,7 +2137,7 @@ module Squared
2134
2137
  end until accept.empty?
2135
2138
  end
2136
2139
  if values
2137
- ret = Array(ret)
2140
+ ret = [ret] unless accept && multiple == -1
2138
2141
  Array(values).each do |val|
2139
2142
  if val.is_a?(Array)
2140
2143
  val, force = val
@@ -16,19 +16,19 @@ module Squared
16
16
  cgroup-parent=b iidfile=p label=q network=b no-cache-filter=b o|output=q platform=q
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
- shared: %w[check load no-cache pull push allow=q call=b? f|file=p metadata-file=p progress=b provenance=q
20
- sbom=q].freeze
19
+ shared: %w[check load no-cache pull push allow=qq call=b? f|file=p metadata-file=p progress=b provenance=b?
20
+ sbom=b?].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
24
- project-directory=p p|project-name=e].freeze,
23
+ common: %w[1 all-resources compatibility dry-run ansi=b env-file=p f|file=p parallel=n profile=b progress=b
24
+ project-directory=p p|project-name=b].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
27
  create: %w[build force-recreate no-build no-recreate quiet-pull remove-orphans y|yes pull=b scale=i].freeze,
28
- exec: %w[d|detach privileged e|env=qq index=i T|no-TTY=b? user=e w|workdir=q].freeze,
28
+ exec: %w[d|detach privileged e|env=qq index=i T|no-tty=!? user=b w|workdir=q].freeze,
29
29
  run: %w[build d|detach no-deps q|quiet quiet-build quiet-pull remove-orphans rm P|service-ports use-aliases
30
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
+ T|no-tty=!? p|publish=q pull=b u|user=b v|volume=qq w|workdir=q].freeze,
32
32
  up: %w[abort-on-container-exit abort-on-container-failure always-recreate-deps attach-dependencies build
33
33
  d|detach force-recreate menu no-build no-color no-deps no-log-prefix no-recreate no-start quiet-build
34
34
  quiet-pull remove-orphans V|renew-anon-volumes timestamps wait w|watch y|yes attach=b
@@ -38,9 +38,9 @@ module Squared
38
38
  }.freeze,
39
39
  container: {
40
40
  create: %w[init i|interactive no-healthcheck oom-kill-disable privileged P|publish-all q|quiet read-only
41
- rm t|tty use-api-socket add-host=q annotation=q a|attach=b blkio-weight=i blkio-weight-device=i
42
- cap-add=b cap-drop=b cgroup-parent=b cgroupns=b cidfile=p device=q device-cgroup-rule=q
43
- device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q
41
+ rm t|tty=!? use-api-socket add-host=q annotation=q a|attach=b blkio-weight=i
42
+ blkio-weight-device=i cap-add=b cap-drop=b cgroup-parent=b cgroupns=b cidfile=p device=q
43
+ device-cgroup-rule=q device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q
44
44
  dns=q dns-option=q dns-search=q domainname=b entrypoint=q e|env=qq env-file=p expose=q gpus=q
45
45
  group-add=b health-cmd=q health-interval=b health-retries=i health-start-interval=q
46
46
  health-start-period=q health-timeout=q hostname=q io-maxbandwidth=b io-maxiops=b ip=b ip6=q ipc=b
@@ -48,13 +48,14 @@ module Squared
48
48
  m|memory=b memory-reservation=b memory-swap=n memory-swappiness=n mount=qq name=b network=b
49
49
  network-alias=b oom-score-adj=b pid=b pids-limit=n platform=q p|publish=q pull=b restart=b
50
50
  runtime=b security-opt=q shm-size=b stop-signal=b stop-timeout=i storage-opt=q sysctl=q tmpfs=q
51
- ulimit=q u|user=b userns=b uts=b v|volume=q volume-driver=b volumes-from=b w|workdir=q].freeze,
51
+ ulimit=q u|user=b userns=b uts=b v|volume=qq volume-driver=b volumes-from=b w|workdir=q].freeze,
52
52
  run: %w[d|detach detach-keys=q sig-proxy=b?].freeze,
53
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
54
54
  cpuset-cpus=b cpuset-mems=b m|memory=b memory-reservation=b memory-swap=n pids-limit=n
55
55
  restart=q].freeze,
56
- exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p u|user=e
56
+ exec: %w[d|detach i|interactive privileged t|tty=!? detach-keys=q e|env=qq env-file=p u|user=b
57
57
  w|workdir=q].freeze,
58
+ rm: %w[f|force l|link v|volumes].freeze,
58
59
  commit: %w[no-pause a|author=q c|change=q m|message=q pause=b?].freeze,
59
60
  inspect: %w[s|size f|format=q].freeze,
60
61
  start: %w[a|attach i|interactive detach-keys=q].freeze,
@@ -81,10 +82,10 @@ module Squared
81
82
  VAL_DOCKER = {
82
83
  run: {
83
84
  common: %w[source src destination dst target readonly ro].freeze,
84
- bind: %w[bind-propagation].freeze,
85
+ bind: %w[bind-create-src bind-propagation].freeze,
85
86
  volume: %w[volume-subpath volume-nocopy volume-opt].freeze,
86
87
  tmpfs: %w[tmpfs-size tmpfs-mode].freeze,
87
- image: %w[image-path].freeze
88
+ image: %w[image-subpath].freeze
88
89
  }.freeze,
89
90
  ls: {
90
91
  compose: %w[Name Image Command Service RunningFor Status Ports CreatedAt ExitCode Health ID Labels
@@ -405,15 +406,15 @@ module Squared
405
406
  end
406
407
 
407
408
  def buildx(flag, opts = [], tag: nil, context: nil, from: nil)
409
+ bx = OPT_DOCKER[:buildx]
408
410
  if flag == :bake && context&.match?(%r{^["']?(https?|git)://}i)
409
- shared = data[:shared].dup.push('f|file=q')
411
+ shared = bx[:shared].dup.push('f|file=q')
410
412
  shared.delete('f|file=p')
411
413
  end
412
414
  cmd, opts = docker_session('buildx', opts: opts)
413
- data = OPT_DOCKER[:buildx]
414
- op = OptionPartition.new(opts, data[:common], cmd, project: self, strict: strict?)
415
+ op = OptionPartition.new(opts, bx[:common], cmd, project: self, strict: strict?)
415
416
  op.append(flag, quote: false)
416
- .parse(data[flag == :bake ? :bake : :build] + (shared || data[:shared]))
417
+ .parse(bx[flag == :bake ? :bake : :build] + (shared || bx[:shared]))
417
418
  case flag
418
419
  when :build, :context
419
420
  append_tag(tag || option('tag', ignore: false) || self.tag)
@@ -424,6 +425,10 @@ module Squared
424
425
  end
425
426
  when :bake
426
427
  append_file(0, index: 3) unless from || op.arg?('f', 'file') || !anypath?(*COMPOSEFILE)
428
+ if op.first == '-'
429
+ op.shift
430
+ op << @output[4] if @output[4]
431
+ end
427
432
  unless op.empty?
428
433
  if !context && op.size > 1 && exist?(op.last, type: 'd')
429
434
  pat = /\btarget\s+"#{Regexp.escape(op.last)}"/
@@ -454,10 +459,11 @@ module Squared
454
459
  docker_session('compose', command, '--', *service)
455
460
  else
456
461
  cmd, opts = docker_session('compose', opts: opts)
457
- op = OptionPartition.new(opts, OPT_DOCKER[:compose][:common], cmd, project: self, strict: strict?)
462
+ cp = OPT_DOCKER[:compose]
463
+ op = OptionPartition.new(opts, cp[:common], cmd, project: self, strict: strict?)
458
464
  append_file(filetype, force: flag == :publish) unless op.arg?('f', 'file')
459
465
  op << flag
460
- op.parse(OPT_DOCKER[:compose].fetch(flag, []))
466
+ op.parse(cp.fetch(flag, []))
461
467
  if flag == :publish
462
468
  id ||= option('tag', ignore: false) || op.shift || tagmain
463
469
  registry ||= option('registry') || op.shift || @oci
@@ -488,10 +494,11 @@ module Squared
488
494
 
489
495
  def container(flag, opts = [], id: nil)
490
496
  cmd, opts = docker_session('container', flag, opts: opts)
491
- data = OPT_DOCKER[:container]
492
- list = data.fetch(flag, [])
493
- list += data[:create] if (rc = flag == :run)
494
- list += data[:update] if rc ||= flag == :create
497
+ rc = flag == :run
498
+ ct = OPT_DOCKER[:container]
499
+ list = ct.fetch(flag, [])
500
+ list += ct[:create] if rc
501
+ list += ct[:update] if rc ||= flag == :create
495
502
  op = OptionPartition.new(opts, list, cmd, project: self, strict: strict?, args: rc || flag == :exec)
496
503
  from = symjoin 'container', flag
497
504
  case flag
@@ -520,21 +527,33 @@ module Squared
520
527
  end
521
528
  end
522
529
  case k
523
- when 'readonly', 'ro'
524
- out << k
530
+ when 'readonly', 'ro', 'volume-nocopy', 'bind-create-src'
531
+ out << k if %w[bind volume].include?(type)
525
532
  next
526
- when 'source', 'src', 'destination', 'dst', 'target', 'volume-subpath', 'image-path'
527
- raise_error ArgumentError, "#{k}: no path value", hint: flag unless v
528
- v = basepath v
533
+ when 'source', 'src', 'destination', 'dst', 'target', 'volume-subpath', 'image-subpath'
534
+ raise_error ArgumentError, "no path value: #{k}", hint: flag unless v
535
+ case k
536
+ when 'source', 'src'
537
+ if type == 'bind'
538
+ v = basepath v
539
+ elsif type == 'tmpfs'
540
+ next
541
+ end
542
+ when 'destination', 'dst', 'target'
543
+ unless v.start_with?('/')
544
+ print_error(Logger::ERROR, "path is not absolute: #{v}", subject: from, hint: k)
545
+ next
546
+ end
547
+ end
529
548
  v = shell_quote(v, option: false, force: false) if q == ''
530
549
  end
531
550
  out << "#{k}=#{q}#{v}#{q}"
532
551
  elsif !silent?
533
- log_message('unrecognized option', subject: from, hint: k)
552
+ puts log_message('unrecognized option', subject: from, hint: k)
534
553
  end
535
554
  end
536
555
  raise_error TypeError, 'none specified', hint: flag unless type
537
- cmd << "--mount type=#{type},#{args.join(',')}"
556
+ op << "--mount type=#{type},#{args.join(',')}"
538
557
  end
539
558
  end
540
559
  append_command(flag, id || tagmain, op.extras)
@@ -543,7 +562,7 @@ module Squared
543
562
  op.append(escape: true, strip: /^:/)
544
563
  when :commit
545
564
  latest = op.shift || tagmain
546
- cmd << id << latest
565
+ op << id << latest
547
566
  raise_error ArgumentError, "unrecognized args: #{op.join(', ')}", hint: flag unless op.empty?
548
567
  return unless confirm_command(cmd.to_s, title: from, target: id, as: latest)
549
568
 
@@ -564,7 +583,7 @@ module Squared
564
583
  else
565
584
  if op.empty?
566
585
  ps, status, no = filter_ps flag, from
567
- cmd << '--no-stream' if flag == :stats
586
+ op << '--no-stream' if flag == :stats
568
587
  list_image(flag, ps, no: no, hint: status, from: from) { |img| run(cmd.temp(img), from: from) }
569
588
  return
570
589
  end
@@ -637,7 +656,7 @@ module Squared
637
656
  registry = op.shift
638
657
  registry ||= option('registry') || @registry unless id.include?('/')
639
658
  end
640
- cmd << shell_quote(tagjoin(registry, id))
659
+ op << shell_quote(tagjoin(registry, id))
641
660
  when :push
642
661
  id ||= option('tag', ignore: false) || op.shift || tagmain
643
662
  registry ||= option('registry') || op.shift || @registry
@@ -645,7 +664,7 @@ module Squared
645
664
  raise_error ArgumentError, 'username/registry not specified', hint: flag unless registry
646
665
  uri = shell_quote tagjoin(registry, id)
647
666
  op << uri
648
- img = docker_output 'image', 'tag', id, uri
667
+ img = docker_output 'image tag', id, uri
649
668
  return unless confirm_command(img.to_s, cmd.to_s, target: id, as: registry, title: from)
650
669
 
651
670
  @session = img
@@ -736,12 +755,12 @@ module Squared
736
755
  session('docker', *cmd, main: false, options: false, **kwargs)
737
756
  end
738
757
 
739
- def append_command(flag, val, list, target: @session, prompt: ':')
740
- list << if list.delete(prompt)
741
- readline('Enter command [args]', force: flag == :exec)
742
- else
743
- env('DOCKER_ARGS')
744
- end
758
+ def append_command(flag, id, list, target: @session, prompt: ':')
759
+ if list.delete(prompt)
760
+ list << readline('Enter command [args]', force: flag == :exec)
761
+ elsif (val = env('DOCKER_ARGS'))
762
+ list << val
763
+ end
745
764
  case flag
746
765
  when :run
747
766
  unless session_arg?('name', target: target)
@@ -750,8 +769,22 @@ module Squared
750
769
  when :exec
751
770
  raise_error ArgumentError, 'nothing to execute', hint: flag if list.empty?
752
771
  end
753
- target << val << list.shift
754
- target << list.join(' && ') unless list.empty?
772
+ target << id
773
+ case list.first
774
+ when '--'
775
+ target.merge(list.drop(1))
776
+ when /\A(--|&&)(\s|\z)/
777
+ target.merge(list)
778
+ else
779
+ target << list.shift
780
+ unless list.empty?
781
+ if list.first.start_with?('-')
782
+ target.merge(list)
783
+ else
784
+ target << list.join(' && ')
785
+ end
786
+ end
787
+ end
755
788
  end
756
789
 
757
790
  def append_file(type, target: @session, index: 2, force: false)
@@ -822,7 +855,7 @@ module Squared
822
855
  pwd_set(from: from) do
823
856
  index = 1
824
857
  all = option('all', prefix: 'docker')
825
- y = from == :'image:rm' && option('y', prefix: 'docker')
858
+ y = from.to_s.end_with?(':rm') && option('y', prefix: 'docker')
826
859
  filter = env('DOCKER_FILTER', filter).to_s
827
860
  pat = if OptionPartition.pattern?(filter)
828
861
  Regexp.new(filter)
@@ -963,7 +996,7 @@ module Squared
963
996
  end
964
997
  cmd.merge(Array(out).map { |val| val.split(/\s+/, 2).first })
965
998
  cmd << args
966
- success?(run(cmd), ctx.start_with?('network', 'tag', 'save'))
999
+ success?(run(cmd, { 'NO_COLOR' => 'true' }), ctx.start_with?('network', 'tag', 'save'))
967
1000
  end
968
1001
 
969
1002
  def filetype(val = dockerfile)
@@ -169,9 +169,10 @@ module Squared
169
169
  fetch: {
170
170
  base: %w[multiple porcelain progress P|prune-tags refetch stdin u|update-head-ok
171
171
  recurse-submodules-default=b?].freeze,
172
- pull: %w[4 6 n t a|append atomic dry-run f|force k|keep negotiate-only prefetch p|prune q|quiet set-upstream
173
- unshallow update-shallow v|verbose deepen=i depth=i j|jobs=i negotiation-tip=q recurse-submodules=v
174
- refmap=q o|server-option=q shallow-exclude=b shallow-since=v upload-pack=q].freeze
172
+ pull: %w[n t 4|ipv4 6|ipv6 a|append atomic dry-run f|force k|keep negotiate-only prefetch p|prune q|quiet
173
+ set-upstream unshallow update-shallow v|verbose deepen=i depth=i j|jobs=i negotiation-tip=q
174
+ recurse-submodules=v refmap=q o|server-option=q shallow-exclude=b shallow-since=v
175
+ upload-pack=q].freeze
175
176
  }.freeze,
176
177
  git: {
177
178
  add: %w[N|intent-to-add].freeze,
@@ -211,7 +212,7 @@ module Squared
211
212
  graph ita-invisible-in-index minimal name-only name-status no-color-moved-ws no-prefix no-renames
212
213
  numstat patch-with-raw patch-with-stat patience pickaxe-all pickaxe-regex raw shortstat summary
213
214
  a|text abbrev=i? anchored=q break-rewrites=b? color=b color-moved=b color-moved-ws=b color-words=q?
214
- diff-algorithm=b diff-filter=e? X|dirstat=b? dirstat-by-file=b? dst-prefix=q find-copies=i?
215
+ diff-algorithm=b diff-filter=q? X|dirstat=b? dirstat-by-file=b? dst-prefix=q find-copies=i?
215
216
  find-object=b find-renames=b? ignore-matching-lines=q ignore-submodules=b? line-prefix=q
216
217
  max-depth=n output=p output-indicator-context=q output-indicator-new=q output-indicator-old=q
217
218
  relative=p rotate-to=p skip-to=p src-prefix=q stat=b? stat-count=i stat-width=i stat-name-width=i
@@ -276,7 +277,7 @@ module Squared
276
277
  checkout: %w[overwrite-ignore guess overlay progress recurse-submodules track].freeze,
277
278
  fetch: {
278
279
  base: %w[auto-gc auto-maintenance write-commit-graph write-fetch-head].freeze,
279
- pull: %w[all ipv4 ipv6 recurse-submodules show-forced-updates tags].freeze
280
+ pull: %w[all recurse-submodules show-forced-updates tags].freeze
280
281
  },
281
282
  grep: %w[color exclude-standard recursive textconv].freeze,
282
283
  log: {
@@ -309,7 +310,7 @@ module Squared
309
310
  }.freeze,
310
311
  rebase: {
311
312
  send: %w[continue skip abort quit].freeze,
312
- value: %w[true false merges interactive].freeze
313
+ value: %w[false true merges interactive].freeze
313
314
  }.freeze,
314
315
  reset: %w[soft mixed hard merge keep recurse-submodules no-recurse-submodules].freeze,
315
316
  revbuild: %w[untracked-files ignore-submodules ignored].freeze
@@ -600,10 +601,10 @@ module Squared
600
601
  when 'i', 'E', 'F', 'P'
601
602
  opts << last
602
603
  else
603
- if last =~ /^(f(-ormat)?)=(.+)$/
604
+ if last =~ /^f(?:-ormat)?=(.+)$/
604
605
  opts.shift
605
606
  opts << "format=#{$1}"
606
- elsif last =~ /^(max(-count)?)=(\d+)$/
607
+ elsif last =~ /^max(?:-count)?=(\d+)$/
607
608
  opts << "max-count=#{$1}"
608
609
  else
609
610
  grep << last
@@ -1200,7 +1201,11 @@ module Squared
1200
1201
  first: (matchpathspec if flag == :push))
1201
1202
  case flag
1202
1203
  when :push
1203
- op.readline('Enter message', option: 'message', quote: true) if op.remove(':')
1204
+ if op.remove(':')
1205
+ op.readline('Enter message', option: 'message', quote: true)
1206
+ else
1207
+ append_message
1208
+ end
1204
1209
  append_pathspec op.extras
1205
1210
  when :pop, :apply, :drop, :branch
1206
1211
  if op.remove(':')
@@ -1816,7 +1821,7 @@ module Squared
1816
1821
  cmd << '--textconv'
1817
1822
  append_value(files.flat_map { |val| Dir[val] }
1818
1823
  .select { |val| projectpath?(val) }
1819
- .map { |val| shell_quote("HEAD:#{val}") })
1824
+ .map { |val| "HEAD:#{val}" })
1820
1825
  source(banner: false)
1821
1826
  return
1822
1827
  when :oneline
@@ -1830,11 +1835,11 @@ module Squared
1830
1835
  else
1831
1836
  opts << format if format
1832
1837
  end
1833
- list = OPT_GIT[:show] + OPT_GIT[:diff][:show] + OPT_GIT[:log][:diff] + OPT_GIT[:log][:diff_context]
1838
+ list = OPT_GIT[:show] + OPT_GIT[:diff][:show] + collect_hash(OPT_GIT[:log], pass: [:base])
1834
1839
  op = OptionPartition.new(opts, list, cmd,
1835
1840
  project: self, strict: strict?,
1836
1841
  no: OPT_GIT[:no][:show] + collect_hash(OPT_GIT[:no][:log], pass: [:base]))
1837
- op.append(delim: true)
1842
+ op.append
1838
1843
  source(exception: false, banner: flag != :oneline)
1839
1844
  end
1840
1845
 
@@ -1885,7 +1890,7 @@ module Squared
1885
1890
  op.add_quote(remote) if remote
1886
1891
  out, banner, from = source(io: true)
1887
1892
  print_item banner
1888
- ret = write_lines(out, grep: op.extras, prefix: "refs/#{flag}/")
1893
+ ret = write_lines(out, grep: op.extras)
1889
1894
  list_result(ret, flag.to_s, grep: op.extras, banner: banner, from: from)
1890
1895
  end
1891
1896
 
@@ -1910,8 +1915,7 @@ module Squared
1910
1915
  when :'sparse-checkout'
1911
1916
  cmd << 'set'
1912
1917
  end
1913
- op = OptionPartition.new(opts, list, cmd, project: self, strict: strict?,
1914
- no: OPT_GIT[:no][flag], single: /\A\d+\z/,
1918
+ op = OptionPartition.new(opts, list, cmd, project: self, strict: strict?, no: OPT_GIT[:no][flag],
1915
1919
  first: case flag
1916
1920
  when :blame, :revert, :'sparse-checkout' then nil
1917
1921
  else matchpathspec
@@ -2185,9 +2189,9 @@ module Squared
2185
2189
  end
2186
2190
  end
2187
2191
 
2188
- def append_pathspec(files = [], target: @session, expect: false, **kwargs)
2192
+ def append_pathspec(files = [], target: @session, expect: false, strict: strict?, **kwargs)
2189
2193
  if session_arg?('pathspec-from-file', target: target)
2190
- OptionPartition.clear(target, files, styles: theme[:inline])
2194
+ OptionPartition.clear(target, files, strict: strict, styles: theme[:inline])
2191
2195
  true
2192
2196
  else
2193
2197
  option('pathspec', target: target) { |val| files = split_escape(val) } if files.empty?
@@ -18,6 +18,7 @@ module Squared
18
18
  pack: %w[ignore-scripts=!? json=!? pack-destination=p].freeze,
19
19
  rebuild: %w[bin-links=! foreground-scripts=!? global=!? ignore-scripts=!? install-links=!?].freeze,
20
20
  'approve-scripts': %w[a|all allow-scripts-pending allow-scripts-pin=!? no-allow-scripts-pin json].freeze,
21
+ 'deny-scripts': %w[a|all json].freeze,
21
22
  no: {
22
23
  install: %w[audit bin-links fund package-lock].freeze
23
24
  }.freeze
@@ -285,7 +286,7 @@ module Squared
285
286
 
286
287
  format_desc action, nil, 'version?,args*'
287
288
  task action, [:version] do |_, args|
288
- path = ->(s) { File.join(ENV['NVM_DIR'], s) }
289
+ path = ->(s) { shell_quote(File.join(ENV['NVM_DIR'], s)) }
289
290
  unless (version = args.version)
290
291
  cmd = ". #{path.call('nvm.sh')} && nvm list --no-colors --no-alias"
291
292
  version = pwd_set(from: :nvm) do
@@ -313,13 +314,41 @@ module Squared
313
314
  outdated flag, args.to_a
314
315
  end
315
316
  when 'package'
316
- format_desc(action, flag, 'opts*', before: case flag
317
- when :dedupe, :rebuild then nil
318
- when :reinstall then 'f/orce?'
319
- else 'name*'
320
- end)
321
- task flag do |_, args|
322
- package flag, args.to_a
317
+ case flag
318
+ when :approve, :deny
319
+ format_desc action, flag, 'name*|:,opts*'
320
+ task flag do |_, args|
321
+ args = args.to_a
322
+ if args.first == ':'
323
+ args.shift
324
+ pwd_set do
325
+ pad = 0
326
+ list = IO.popen(npm_output('approve-scripts --allow-scripts-pending').to_s)
327
+ .each_with_object([]) do |line, out|
328
+ next unless line =~ /^\s+([a-z\d@][^@]*)@(\S+)/
329
+
330
+ pad = [pad, $1.size].max
331
+ out << [$1, $2]
332
+ end
333
+ .map { |name, ver| name.ljust(pad + 4) + ver }
334
+ if list.empty?
335
+ puts log_message('no packages to review', subject: name, hint: "#{flag}-scripts")
336
+ exit 0
337
+ end
338
+ args.concat(choice_index('Select packages', list, multiple: true, column: /^(\S+)/))
339
+ end
340
+ end
341
+ package flag, args
342
+ end
343
+ else
344
+ format_desc(action, flag, 'opts*', before: case flag
345
+ when :dedupe, :rebuild then nil
346
+ when :reinstall then 'f/orce?'
347
+ else 'name*'
348
+ end)
349
+ task flag do |_, args|
350
+ package flag, args.to_a
351
+ end
323
352
  end
324
353
  when 'bump'
325
354
  break unless version
@@ -830,17 +859,17 @@ module Squared
830
859
  end
831
860
  a = a.ljust(col1)
832
861
  b = b.ljust(col2)
833
- sub_style! b, theme[:current] if theme[:current] && !stdin?
862
+ b = sub_style b, theme[:current] if theme[:current] && !stdin?
834
863
  if cur == -1
835
864
  c = 'SKIP'
836
865
  elsif modified == cur
837
866
  c = 'FAIL'
838
867
  elsif !stdin?
839
868
  if d == 1
840
- sub_style! a, theme[:major]
841
- sub_style! c, :bold, color(:green)
869
+ a = sub_style a, theme[:major]
870
+ c = sub_style c, :bold, color(:green)
842
871
  else
843
- sub_style!(c, **opt_style(color(d == 3 ? :green : :yellow), SEM_VER, d))
872
+ c = sub_style(c, **opt_style(color(d == 3 ? :green : :yellow), SEM_VER, d))
844
873
  end
845
874
  g = item
846
875
  end
@@ -913,8 +942,8 @@ module Squared
913
942
  b = sub_style b.ljust(col2), color(d ? :red : :yellow)
914
943
  c = c.ljust(col3)
915
944
  unless d
916
- sub_style! a, theme[:active]
917
- sub_style! c, color(:green)
945
+ a = sub_style a, theme[:active]
946
+ c = sub_style c, color(:green)
918
947
  pending += 1
919
948
  end
920
949
  puts "#{pad.call(i, avail)}. #{(a + c + b).subhint(d ? 'locked' : 'latest')}"
@@ -726,7 +726,7 @@ module Squared
726
726
  op.clear(pass: false)
727
727
  else
728
728
  if op.empty?
729
- op << "#{dist.call}/*"
729
+ op.add_path(dist.call, '*')
730
730
  else
731
731
  op.add_path
732
732
  end
@@ -87,8 +87,25 @@ module Squared
87
87
 
88
88
  def strip(val)
89
89
  val = shell_split val if val.is_a?(String)
90
- Array(val).map { |s| s.sub(OPT_SINGLE, '\1=\2').sub(OPT_VALUE, '\1=\2').sub(OPT_NAME, '\2') }
91
- .reject(&:empty?)
90
+ ret = []
91
+ pass = -1
92
+ (args = Array(val)).each_with_index do |s, i|
93
+ next if s.empty? || pass == i
94
+
95
+ if s == '--'
96
+ ret << s << args[i.succ..-1].join(' ')
97
+ break
98
+ end
99
+ next ret << s unless s.start_with?('-')
100
+
101
+ if !s.include?('=') && (j = args[i.succ]) && !j.start_with?('-')
102
+ ret << "#{s.sub(/^-{1,2}/, '')}=#{j}"
103
+ pass = i.succ
104
+ else
105
+ ret << s.sub(OPT_SINGLE, '\1=\2').sub(OPT_VALUE, '\1=\2').sub(OPT_NAME, '\2')
106
+ end
107
+ end
108
+ ret
92
109
  end
93
110
 
94
111
  def select(list, bare: true, no: true, single: false, double: false)
@@ -152,8 +169,11 @@ module Squared
152
169
  end
153
170
 
154
171
  def pattern?(val)
172
+ Regexp.new(val)
155
173
  val.start_with?('\A', '^') || val.end_with?('\z', '$') ||
156
174
  val.match?(/[.)][*+?]|\(\?[:=!><]|\\[dsw\d]|\[.+\]|\{\d+,?\d*\}/i)
175
+ rescue RegexpError
176
+ false
157
177
  end
158
178
 
159
179
  private
@@ -251,13 +271,13 @@ module Squared
251
271
  else
252
272
  [flag]
253
273
  end
274
+ bare.concat(mod) if val.chomp!('?')
275
+ m.concat(mod) if val.chomp!('m')
254
276
  case val[n.succ]
255
277
  when 'e'
256
278
  e.concat(mod)
257
279
  when 'b'
258
280
  b.concat(mod)
259
- when 'm'
260
- m.concat(mod)
261
281
  when 'q'
262
282
  qq.concat(mod) if val[n + 2] == 'q'
263
283
  q.concat(mod)
@@ -276,11 +296,7 @@ module Squared
276
296
  when '+'
277
297
  ml.concat(mod)
278
298
  bare.concat(mod)
279
- else
280
- next
281
299
  end
282
- m.concat(mod) if val[n + 2] == 'm'
283
- bare.concat(mod) if val.end_with?('?')
284
300
  else
285
301
  bare << val
286
302
  mod = [val]
@@ -315,7 +331,7 @@ module Squared
315
331
  end
316
332
  numtype = [
317
333
  [i, /\A\d+\z/],
318
- [f, /\A\d*(?:\.\d+)?\z/],
334
+ [f, /\A(\d+(\.\d*)?|\d*\.\d+)\z/],
319
335
  [si, /\A-?\d+\z/]
320
336
  ].freeze
321
337
  numcheck = ->(k, v) { numtype.any? { |flag, pat| flag.include?(k) && v.match?(pat) } }
@@ -348,6 +364,10 @@ module Squared
348
364
  if opt =~ OPT_VALUE
349
365
  key = $1
350
366
  val = $2
367
+ if val =~ /\A(["'])(.+)\1\z/
368
+ val = $2
369
+ double = $1 == '"'
370
+ end
351
371
  has = lambda do |a|
352
372
  return true if a.include?(key)
353
373
  return false unless (k = a.find { |s| s.end_with?(':*') })
@@ -355,12 +375,14 @@ module Squared
355
375
  key.start_with?(k.chomp('*')) && !key.end_with?(':')
356
376
  end
357
377
  kwargs = { sep: se[key] || sep, merge: has.call(m), switch: sw[key] }
378
+ kwargs[:double] = double unless double.nil?
358
379
  if has.call(e) || (has.call(bl) && %w[true false].include?(val))
359
380
  add shell_option(key, val, **kwargs)
360
381
  elsif has.call(q)
361
- add quote_option(key, val, double: has.call(qq), **kwargs)
382
+ kwargs[:double] = true if has.call(qq, key)
383
+ add quote_option(key, val, **kwargs)
362
384
  elsif has.call(p)
363
- if val.match?(/\A(["']).+\1\z/)
385
+ if !double.nil?
364
386
  add shell_option(key, val, escape: false, **kwargs)
365
387
  elsif path
366
388
  add quote_option(key, path + val, **kwargs)
@@ -280,7 +280,7 @@ module Squared
280
280
  env('REPO_OPTIONS', **kwargs) { |val| cmd << val } if options
281
281
  cmd = cmd.join(' ')
282
282
  puts log_message(cmd, subject: main, hint: root) if verbose
283
- Common::System.shell(cmd, chdir: root, exception: exception)
283
+ Common::System.shell(cmd, chdir: root, exception: exception || env('REPO_FAIL', equals: %w[1 true]))
284
284
  end
285
285
 
286
286
  def repo_bin
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squared
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.10
4
+ version: 0.7.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham
@@ -125,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
125
  - !ruby/object:Gem::Version
126
126
  version: '0'
127
127
  requirements: []
128
- rubygems_version: 4.0.15
128
+ rubygems_version: 4.0.21
129
129
  specification_version: 4
130
130
  summary: Rake task generator for managing multi-language workspaces.
131
131
  test_files: []