squared 0.5.10 → 0.5.11

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: 1614a1b7a4674c33cbc895cc8ee6e475ec2ed577f431a52df251c9b1415b128f
4
- data.tar.gz: f24f7926cda7af396f681670f35008473d56bd35f29b7c3a982826be9b2ffaa7
3
+ metadata.gz: 56af2850e96c00e48e1511b20fc61c5f0d9969220b4b070a6c61c02ce6489e97
4
+ data.tar.gz: 83749c3414fa0496dfa64fb3ec0846af2205b1c4483ecbd44e72ed2d976c7852
5
5
  SHA512:
6
- metadata.gz: c8e181a06665254466e0fffc3cb1c00e33ebeaa56354689a1b40b4c7a302e5e3554ceca1b45dea389eff4fd8653eec8e756fc8fe9921447d28fd5cd62b100235
7
- data.tar.gz: e6ed8bbcdb2a38741f0562bf5ff00ee638d359ea0af7674c5e6346dd125e692e350999e027c560641b708ec2dbcd3438f184ab4565387a5adbe942ef014a264d
6
+ metadata.gz: 4fbc69f9efe06c1d2ceba44c58854ca31b0a7e50a6fe89c01e3aeff05830efae2f7bf07f068163352f6c54f9d347a5db11b308a8f0b3f3b64914ac6b0035743b
7
+ data.tar.gz: 7aada08d98786700e652f0a78e5ddeda72ada420ec9d89cffc937f706b27da4800374231d086b67be8ae748199d0229a02fb95a9dfaac349fff6c40997ab5099
data/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.11] - 2025-10-18
4
+
5
+ ### Fixed
6
+
7
+ - Ruby command version did not parse asdf output in Go.
8
+ - Git command submodule action branch did not provide name argument.
9
+
10
+ ## [0.4.25] - 2025-10-18
11
+
12
+ ### Fixed
13
+
14
+ - Project groups did not have their own copy of base events.
15
+
16
+ ## [0.4.24] - 2025-10-17
17
+
18
+ ### Added
19
+
20
+ - Repo task [init|all] can bypass dev? copy requirement with REPO_STAGE=4.
21
+
22
+ ### Changed
23
+
24
+ - Node command outdated does not check PNPM minimum version.
25
+
26
+ ### Fixed
27
+
28
+ - Project base rescue error handling used reversed parameters.
29
+ - Project absolute paths did not append wildcard with trailing slash.
30
+ - Powershell commands did not escape nested double quotes.
31
+ - OptionPartition did not strip flags without a value.
32
+ - Project base method add did not use parent context.
33
+ - Application property pipe did not parse numeric values.
34
+
3
35
  ## [0.5.10] - 2025-10-11
4
36
 
5
37
  ### Fixed
@@ -1121,6 +1153,7 @@
1121
1153
 
1122
1154
  - Changelog was created.
1123
1155
 
1156
+ [0.5.11]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.11
1124
1157
  [0.5.10]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.10
1125
1158
  [0.5.9]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.9
1126
1159
  [0.5.8]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.8
@@ -1132,6 +1165,8 @@
1132
1165
  [0.5.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.2-ruby
1133
1166
  [0.5.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.1-ruby
1134
1167
  [0.5.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.0-ruby
1168
+ [0.4.25]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.25
1169
+ [0.4.24]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.24
1135
1170
  [0.4.23]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.23
1136
1171
  [0.4.22]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.22
1137
1172
  [0.4.21]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.21
data/README.md CHANGED
@@ -745,7 +745,7 @@ REPO_SYNC # 0,1
745
745
  REPO_URL # manifest repository
746
746
  REPO_MANIFEST # e.g. latest,nightly,prod
747
747
  REPO_GROUPS # e.g. base,prod,docs
748
- REPO_STAGE # 0,1,2,3
748
+ REPO_STAGE # 0,1,2,3,4
749
749
  REPO_SUBMODULLES # 0,1
750
750
  REPO_TIMEOUT # confirm dialog (seconds)
751
751
  ```
@@ -180,8 +180,9 @@ module Squared
180
180
  args = args.map(&:to_s)
181
181
  if level.is_a?(::Numeric)
182
182
  if append && respond_to?(:log)
183
- ref = log rescue nil
184
- ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(Logger)
183
+ (log rescue nil).tap do |ref|
184
+ ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(::Logger)
185
+ end
185
186
  end
186
187
  return false if !pass && level < ARG[:LEVEL]
187
188
  end
@@ -200,7 +201,7 @@ module Squared
200
201
  def log_console(*args, pipe: 1)
201
202
  return if args.first == false && args.size == 1
202
203
 
203
- if pipe.is_a?(Pathname)
204
+ if pipe.is_a?(::Pathname)
204
205
  begin
205
206
  File.open(pipe, 'a') do |f|
206
207
  br = File::SEPARATOR == '\\' ? "\r\n" : "\n"
@@ -219,7 +220,8 @@ module Squared
219
220
  module_function
220
221
 
221
222
  def message(*args, hint: nil, empty: false, space: ARG[:SPACE])
222
- (empty ? args.reject { |val| val.nil? || val.empty? } : args).join(space) + (hint ? " (#{hint})" : '')
223
+ (empty ? args.reject { |val| val.nil? || (val.respond_to?(:empty?) && val.empty?) } : args)
224
+ .join(space) + (hint ? " (#{hint})" : '')
223
225
  end
224
226
 
225
227
  def emphasize(val, title: nil, footer: nil, right: false, cols: nil, sub: nil, pipe: nil,
@@ -233,7 +235,7 @@ module Squared
233
235
  lines = val.map(&:to_s)
234
236
  else
235
237
  lines = val.to_s.lines(chomp: true)
236
- lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(StandardError))
238
+ lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(::StandardError))
237
239
  end
238
240
  n = cols || max.call(lines)
239
241
  if $stdout.tty?
@@ -56,7 +56,7 @@ module Squared
56
56
  min = [min, max].min
57
57
  if auto
58
58
  msg = "#{msg}: [1-#{max}#{if multiple
59
- "|,#{multiple.is_a?(Numeric) ? "{#{multiple}}" : ''}"
59
+ "|,#{multiple.is_a?(::Numeric) ? "{#{multiple}}" : ''}"
60
60
  end}] "
61
61
  end
62
62
  end
@@ -113,18 +113,18 @@ module Squared
113
113
  elsif block_given?
114
114
  Readline.readmultiline(msg, history, &blk)
115
115
  else
116
- Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val) } }
116
+ Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val.to_s) } }
117
117
  end
118
118
  end
119
119
  case force
120
120
  when ::TrueClass, ::FalseClass
121
121
  msg = "#{msg} %s " % if multiline
122
- multiline.is_a?(::Enumerable) ? "{#{multiline.join('|')}}" : multiline
122
+ multiline.is_a?(::Enumerable) ? "{#{multiline.to_a.join('|')}}" : multiline
123
123
  else
124
124
  "(#{force ? 'required' : 'optional'}):"
125
125
  end
126
126
  ret = (prompt.call || '').strip
127
- multiline.each { |val| break if ret.delete_suffix!(val) } if multiline.is_a?(::Enumerable)
127
+ multiline.each { |val| break if ret.delete_suffix!(val.to_s) } if multiline.is_a?(::Enumerable)
128
128
  exit 1 if force && ret.empty?
129
129
  ret
130
130
  else
@@ -16,15 +16,15 @@ module Squared
16
16
  elsif !r[3] || r[6]
17
17
  return val
18
18
  end
19
- if r[7].match?(/\A["']/)
20
- opt = "#{r[7]}#{r[7][0]}"
21
- elsif r[7].match?(/["']\z/)
22
- opt = "#{r[7][-1]}#{r[7]}"
23
- else
24
- return val unless r[7].match?(/\s/)
25
-
26
- opt = r[7]
27
- end
19
+ opt = if r[7].match?(/\A["']/)
20
+ "#{r[7]}#{r[7][0]}"
21
+ elsif r[7].match?(/["']\z/)
22
+ "#{r[7][-1]}#{r[7]}"
23
+ else
24
+ return val unless r[7].match?(/\s/)
25
+
26
+ r[7]
27
+ end
28
28
  r[1] + (data ? data[2] : r[2]) + r[4] + shell_quote(opt, double: double, force: force, override: override)
29
29
  elsif option && val =~ /\A([^=]+)=(.+)\z/m
30
30
  return val if $2.match?(/\A(["']).+\1\z/m)
@@ -69,15 +69,15 @@ module Squared
69
69
  escape = false
70
70
  override = true
71
71
  end
72
- if flag[0] == '-'
73
- b = flag[1] == '-' ? '=' : ' '
74
- elsif flag.size == 1
75
- a = '-'
76
- b = merge ? '' : ' '
77
- else
78
- a = '--'
79
- b = '='
80
- end
72
+ b = if flag[0] == '-'
73
+ flag[1] == '-' ? '=' : ' '
74
+ elsif flag.size == 1
75
+ a = '-'
76
+ merge ? '' : ' '
77
+ else
78
+ a = '--'
79
+ '='
80
+ end
81
81
  "#{a}#{flag}#{unless val.nil?
82
82
  "#{b}#{if escape
83
83
  shell_escape(val, quote: quote, double: double, override: override)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.5.10'
4
+ VERSION = '0.5.11'
5
5
  end
@@ -140,7 +140,7 @@ module Squared
140
140
  return unless @pipe.is_a?(Pathname)
141
141
 
142
142
  msg = "Session started on #{Time.now} by #{@main}"
143
- bord = '#' * s.size
143
+ bord = '#' * msg.size
144
144
  puts bord, msg, bord
145
145
  end
146
146
 
@@ -323,17 +323,9 @@ module Squared
323
323
  end
324
324
 
325
325
  def add(path, project = nil, **kwargs, &blk)
326
- kwargs = @withargs.yield_self { |data| data.dup.update(kwargs) } if @withargs
327
- ref = if kwargs.key?(:ref)
328
- kwargs = kwargs.dup unless @withargs
329
- kwargs.delete(:ref)
330
- elsif @ref.is_a?(Symbol)
331
- @ref
332
- end
333
- if @group.is_a?(String) && !kwargs.key?(:group)
334
- kwargs = kwargs.dup unless @withargs
335
- kwargs[:group] = @group
336
- end
326
+ kwargs = Support.hashdup(@withargs).update(kwargs) if @withargs
327
+ ref = kwargs.key?(:ref) ? kwargs.delete(:ref) : @ref
328
+ kwargs[:group] = @group if @group && !kwargs.key?(:group)
337
329
  path = root + path
338
330
  project = (project || path.basename).to_s
339
331
  name = task_name project
@@ -65,11 +65,13 @@ module Squared
65
65
 
66
66
  @@tasks = {}
67
67
  @@graph = { _: [] }
68
- @@asdf = if File.exist?("#{Dir.home}/.asdf/asdf.sh")
69
- [Pathname.new("#{Dir.home}/.asdf"), 15]
70
- elsif ENV['ASDF_DATA_DIR']
71
- [Pathname.new(ENV['ASDF_DATA_DIR']), 16]
72
- end
68
+ @@asdf = Pathname.new("#{Dir.home}/.asdf").yield_self do |path|
69
+ if path.join('asdf.sh').exist?
70
+ [path, 15]
71
+ elsif ENV['ASDF_DATA_DIR']
72
+ [Pathname.new(ENV['ASDF_DATA_DIR']), 16]
73
+ end
74
+ end
73
75
  @@print_order = 0
74
76
 
75
77
  subtasks({
@@ -389,6 +391,7 @@ module Squared
389
391
  version, opts = choice_index('Select a version',
390
392
  @asdf[1].children
391
393
  .map(&:basename)
394
+ .sort { |a, b| b <=> a }
392
395
  .append('latest', 'system'),
393
396
  force: true, accept: [['Confirm?', false, true]],
394
397
  values: ['Options'])
@@ -437,10 +440,11 @@ module Squared
437
440
  end
438
441
  return self unless projectpath?(path = basepath(path)) && checkdir?(path)
439
442
 
440
- kwargs = @withargs.yield_self { |data| data.dup.update(kwargs) } if @withargs
441
- kwargs[:group] = group unless kwargs.key?(:group)
443
+ kwargs = hashdup(@withargs).update(kwargs) if @withargs
444
+ kwargs[:group] = group if group && !kwargs.key?(:group)
442
445
  kwargs[:ref] = ref unless kwargs.key?(:ref)
443
446
  parent = self
447
+ proj = nil
444
448
  name = case name
445
449
  when String, Symbol
446
450
  name.to_s
@@ -449,9 +453,10 @@ module Squared
449
453
  end
450
454
  workspace.add(path, name, **kwargs) do
451
455
  __send__ :parent_set, parent
452
- @children << self
456
+ proj = self
453
457
  instance_eval(&blk) if block_given?
454
458
  end
459
+ @children << proj
455
460
  self
456
461
  end
457
462
 
@@ -477,9 +482,9 @@ module Squared
477
482
  if args.empty?
478
483
  return unless from == :run
479
484
 
480
- run_b(@run, sync: sync, from: from) if series?(@run)
481
- args = @output
482
485
  banner = verbosetype > 1 if from_base?('build')
486
+ run_b(@run, sync: sync, from: from, banner: banner) if series?(@run)
487
+ args = @output
483
488
  end
484
489
  if args.first.is_a?(Struct)
485
490
  f, blk = args.first.to_a
@@ -513,11 +518,9 @@ module Squared
513
518
  else
514
519
  cmd, opts, var, flags, extra = args
515
520
  end
516
- if cmd.is_a?(Proc) || cmd.is_a?(Method)
517
- run_b(cmd, sync: sync, from: from)
518
- return
519
- end
520
521
  if cmd
522
+ return run_b(cmd, sync: sync, from: from) if cmd.is_a?(Proc) || cmd.is_a?(Method)
523
+
521
524
  cmd = as_get(cmd, from)
522
525
  opts = compose(opts, script: false) if opts && respond_to?(:compose)
523
526
  flags = append_hash(flags, target: []).join(' ') if flags.is_a?(Hash)
@@ -559,7 +562,7 @@ module Squared
559
562
  proj.__send__(meth, sync: sync)
560
563
  next
561
564
  rescue StandardError => e
562
- on_error(:prereqs, e, exception: true)
565
+ on_error(e, :prereqs, exception: true)
563
566
  end
564
567
  end
565
568
  print_error(name, 'method not found', subject: 'prereqs', hint: meth)
@@ -579,7 +582,7 @@ module Squared
579
582
  end
580
583
 
581
584
  def doc(*, sync: invoked_sync?('doc'), **)
582
- run_b(@doc, sync: sync, from: :doc, banner: from_base?('doc') ? verbosetype > 1 : verbose)
585
+ run_b(@doc, sync: sync, banner: from_base?('doc') ? verbose? : verbosetype > 0, from: :doc)
583
586
  end
584
587
 
585
588
  def lint(*, sync: invoked_sync?('lint'), **)
@@ -600,9 +603,9 @@ module Squared
600
603
  on :first, :clean unless pass
601
604
  case @clean
602
605
  when Struct
603
- if (any = instance_eval(&@clean.block) || @clean.run)
606
+ if (val = instance_eval(&@clean.block) || @clean.run)
604
607
  temp = @clean
605
- @clean = any
608
+ @clean = val
606
609
  clean(*args, sync: sync, pass: true, **kwargs)
607
610
  @clean = temp
608
611
  end
@@ -620,7 +623,7 @@ module Squared
620
623
  entry = basepath(val = val.to_s)
621
624
  if entry.directory? && val.match?(%r{[\\/]\z})
622
625
  log&.warn "rm -rf #{entry}"
623
- rm_rf(entry, verbose: verbose)
626
+ rm_rf(entry, verbose: verbosetype > 0)
624
627
  else
625
628
  log&.warn "rm #{entry}"
626
629
  (val.include?('*') ? Dir[entry] : [entry]).each do |file|
@@ -659,7 +662,7 @@ module Squared
659
662
  end
660
663
  ret = graph_branch(self, data, tasks, out, sync: sync, pass: pass)
661
664
  rescue StandardError => e
662
- on_error(:graph, e, exception: true)
665
+ on_error(e, :graph, exception: true)
663
666
  else
664
667
  if out
665
668
  [out, ret]
@@ -718,7 +721,7 @@ module Squared
718
721
  case f.content_type
719
722
  when 'application/zip'
720
723
  ext = 'zip'
721
- when 'application/x-gzip'
724
+ when %r{application/(?:x-)?gzip}
722
725
  ext = 'tgz'
723
726
  when 'application/x-xz'
724
727
  ext = 'txz'
@@ -780,9 +783,7 @@ module Squared
780
783
  break unless entry.directory?
781
784
 
782
785
  i = 0
783
- while (dest = target + "#{File.basename(file)}-#{i}").exist?
784
- i += 1
785
- end
786
+ i += 1 while (dest = target + "#{File.basename(file)}-#{i}").exist?
786
787
  FileUtils.mv(entry, dest)
787
788
  dest.each_child { |child| FileUtils.mv(child, target) }
788
789
  dest.rmdir
@@ -822,7 +823,7 @@ module Squared
822
823
  cmd << '--no-header' unless legacy
823
824
  cmd << name
824
825
  end
825
- print_success if success?(run(from: :"asdf:#{flag}")) && flag == :set
826
+ print_success if success?(run(from: :"asdf:#{flag}"), flag == :set)
826
827
  end
827
828
 
828
829
  def first(key, *args, **kwargs, &blk)
@@ -870,7 +871,7 @@ module Squared
870
871
  def run(cmd = @session, var = nil, exception: self.exception, sync: true, from: nil, banner: true, chdir: path,
871
872
  interactive: nil, hint: nil, **)
872
873
  unless cmd
873
- print_error('no command given', subject: project, hint: from || 'unknown', pass: true)
874
+ print_error('no command session started', subject: project, hint: from, pass: true)
874
875
  return
875
876
  end
876
877
  cmd = cmd.target if cmd.is_a?(OptionPartition)
@@ -908,7 +909,7 @@ module Squared
908
909
  ret = shell(*args, chdir: chdir, exception: exception)
909
910
  end
910
911
  rescue StandardError => e
911
- on_error(from, e, exception: true)
912
+ on_error(e, from, exception: true)
912
913
  false
913
914
  else
914
915
  on :last, from
@@ -1120,8 +1121,8 @@ module Squared
1120
1121
  def run_b(obj, **kwargs)
1121
1122
  case obj
1122
1123
  when Struct
1123
- if (any = instance_eval(&obj.block) || obj.run)
1124
- run_b(any, **kwargs)
1124
+ if (val = instance_eval(&obj.block) || obj.run)
1125
+ run_b(val, **kwargs)
1125
1126
  end
1126
1127
  when Proc
1127
1128
  instance_eval(&obj)
@@ -1687,8 +1688,8 @@ module Squared
1687
1688
  confirm "#{a}: #{b}#{c} #{sub_style(ver.rjust(col1 > 0 ? 10 : 0), styles: theme[:inline])} ", d
1688
1689
  end
1689
1690
 
1690
- def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil,
1691
- multiple: false, force: true, **kwargs)
1691
+ def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil, multiple: false,
1692
+ force: true, **kwargs)
1692
1693
  puts if !series && !printfirst?
1693
1694
  msg = "#{msg} (optional)" unless force
1694
1695
  unless (ret = choice(msg, list, multiple: multiple, force: force, **kwargs)) && !ret.empty?
@@ -1704,13 +1705,10 @@ module Squared
1704
1705
  if accept
1705
1706
  hint = Array(ret).map { |val| sub_style(val, styles: theme[:inline]) }.join(', ')
1706
1707
  accept = Array(accept).map { |val| Array(val) }
1707
- if accept.any? { |val| val[1] == true }
1708
- ret = [ret]
1709
- multiple = -1
1710
- end
1708
+ ret = Array(ret) if accept.any? { |val| val[1] == true }
1711
1709
  loop do
1712
1710
  item = accept.first
1713
- c = confirm("#{item[0]}#{a ? " [#{hint}]" : ''}", item[2] ? 'Y' : 'N', timeout: 60)
1711
+ c = confirm("#{item[0]}#{hint ? " [#{hint}]" : ''}", item[2] ? 'Y' : 'N', timeout: 60)
1714
1712
  if item[1] == true
1715
1713
  ret << c
1716
1714
  elsif !c
@@ -1723,8 +1721,8 @@ module Squared
1723
1721
  exit 1 unless accept.empty?
1724
1722
  end
1725
1723
  if values
1726
- ret = [ret] unless accept && multiple == -1
1727
- values.each do |val|
1724
+ ret = Array(ret)
1725
+ Array(values).each do |val|
1728
1726
  if val.is_a?(Array)
1729
1727
  val, force = val
1730
1728
  else
@@ -1757,21 +1755,17 @@ module Squared
1757
1755
  end
1758
1756
 
1759
1757
  def command(*args)
1760
- if workspace.powershell?
1761
- "powershell.exe -Command \"& {#{args.join(' ; ')}}\""
1762
- else
1763
- args.join(' && ')
1764
- end
1758
+ return args.join(' && ') unless workspace.powershell?
1759
+
1760
+ "powershell.exe -Command #{shell_quote("& {#{args.join(' ; ')}}", option: false, double: true)}"
1765
1761
  end
1766
1762
 
1767
1763
  def relativepath(*list, all: false)
1768
1764
  return [] if list.empty?
1769
1765
 
1770
1766
  list.flatten.map! { |val| Pathname.new(val) }.select { |val| projectpath?(val) }.map! do |val|
1771
- val = val.absolute? ? val.relative_path_from(path).to_s : val.to_s
1772
- val = val[2..-1] if val.start_with?('./')
1773
- val = "#{val}*" if all && val.end_with?('/')
1774
- val
1767
+ ret = (val.absolute? ? val.relative_path_from(path) : val.cleanpath).to_s
1768
+ all && val.to_s.end_with?('/') ? "#{ret}/*" : ret
1775
1769
  end
1776
1770
  end
1777
1771
 
@@ -1819,10 +1813,10 @@ module Squared
1819
1813
  return 1 if a.empty?
1820
1814
 
1821
1815
  a, b = [a.first, b.first].map! do |c|
1822
- begin
1823
- d = Integer(c[5]).to_s
1816
+ d = begin
1817
+ Integer(c[5]).to_s
1824
1818
  rescue StandardError
1825
- d = c[5] ? '-1' : '0'
1819
+ c[5] ? '-1' : '0'
1826
1820
  end
1827
1821
  [c[0], c[2], c[4] || '0', d]
1828
1822
  end
@@ -1855,8 +1849,7 @@ module Squared
1855
1849
  end
1856
1850
 
1857
1851
  def color(val)
1858
- ret = theme[val]
1859
- ret && !ret.empty? ? ret : [val]
1852
+ (ret = theme[val]) && !ret.empty? ? ret : [val]
1860
1853
  end
1861
1854
 
1862
1855
  def colormap(val)
@@ -2074,9 +2067,8 @@ module Squared
2074
2067
  end
2075
2068
 
2076
2069
  def projectpath?(val)
2077
- Pathname.new(val).cleanpath.yield_self do |file|
2078
- file.absolute? ? file.to_s.start_with?(File.join(path, '')) : !file.to_s.start_with?(File.join('..', ''))
2079
- end
2070
+ ret = Pathname.new(val).cleanpath
2071
+ ret.absolute? ? ret.to_s.start_with?(File.join(path, '')) : !ret.to_s.start_with?(File.join('..', ''))
2080
2072
  end
2081
2073
 
2082
2074
  def checkdir?(val)
@@ -2151,6 +2143,10 @@ module Squared
2151
2143
  !!verbose && !stdin?
2152
2144
  end
2153
2145
 
2146
+ def verbose?
2147
+ verbosetype > 1
2148
+ end
2149
+
2154
2150
  def warning?
2155
2151
  workspace.warning
2156
2152
  end
@@ -2182,6 +2178,10 @@ module Squared
2182
2178
  Workspace::Support.hashlist
2183
2179
  end
2184
2180
 
2181
+ def hashdup
2182
+ Workspace::Support.hashdup
2183
+ end
2184
+
2185
2185
  def borderstyle
2186
2186
  workspace.banner_get(*@ref, group: group)&.border || theme[:border]
2187
2187
  end
@@ -113,7 +113,7 @@ module Squared
113
113
  return unless dockerfile(file).exist?
114
114
 
115
115
  @context = context
116
- @tag = tag || tagname("#{@project}:#{@version || 'latest'}")
116
+ self.tag = tag || tagname("#{@project}:#{@version || 'latest'}")
117
117
  @mounts = mounts
118
118
  @secrets = secrets
119
119
  @registry = tagjoin registry, kwargs[:username]
@@ -206,7 +206,7 @@ module Squared
206
206
  end
207
207
  end
208
208
  else
209
- format_desc(action, flag, 'opts*,id/name', after: flag == :update ? '+' : '*')
209
+ format_desc action, flag, "opts*,id/name#{flag == :update ? '+' : '*'}"
210
210
  task flag do |_, args|
211
211
  container flag, args.to_a
212
212
  end
@@ -533,7 +533,7 @@ module Squared
533
533
  list_image(flag, docker_output('image ls -a'), from: from) do |val|
534
534
  op << val
535
535
  if flag == :tag
536
- op << tagname("#{@project}:#{op.first}")
536
+ op << tagname("#{project}:#{op.first}")
537
537
  break
538
538
  end
539
539
  end
@@ -554,7 +554,7 @@ module Squared
554
554
  banner = false
555
555
  end
556
556
  ret = run(cmd, sync: sync, exception: exception, banner: banner, from: from)
557
- print_success if success?(ret) && (flag == :tag || flag == :save)
557
+ print_success if success?(ret, flag == :tag || flag == :save)
558
558
  end
559
559
 
560
560
  def network(flag, opts = [], target: nil)
@@ -656,13 +656,14 @@ module Squared
656
656
  when 2, 4
657
657
  return
658
658
  when 3
659
- return unless COMPOSEFILE.map { |val| basepath(val) }.select(&:exist?).size > 1
659
+ return unless COMPOSEFILE.select { |val| basepath(val).exist? }.size > 1
660
660
  end
661
661
  end
662
662
  files = Array(@file).map { |val| quote_option('file', basepath(val)) }
663
663
  if target.is_a?(Set)
664
664
  opts = target.to_a.insert(index, *files)
665
- target.clear.merge(opts)
665
+ target.clear
666
+ .merge(opts)
666
667
  else
667
668
  target.insert(index, *files)
668
669
  end
@@ -678,7 +679,7 @@ module Squared
678
679
  def append_tag(val, target: @session)
679
680
  case val
680
681
  when String
681
- val.split(',')
682
+ split_escape val
682
683
  when Array
683
684
  val
684
685
  else
@@ -820,7 +821,7 @@ module Squared
820
821
  end
821
822
  cmd.merge(Array(out).map! { |val| parse.call(val) })
822
823
  cmd << args
823
- print_success if success?(run(cmd)) && ctx.start_with?(/(?:network|tag|save)/)
824
+ print_success if success?(run(cmd), ctx.start_with?(/(?:network|tag|save)/))
824
825
  end
825
826
  end
826
827
 
@@ -408,10 +408,11 @@ module Squared
408
408
 
409
409
  case flag
410
410
  when :branch
411
- format_desc action, flag, 'path,opts*'
412
- task flag, [:path] do |_, args|
411
+ format_desc action, flag, 'path,name?'
412
+ task flag, [:path, :name] do |_, args|
413
413
  path = param_guard(action, flag, args: args, key: :path)
414
- submodule(flag, args.extras, path: path)
414
+ branch = args.name
415
+ submodule(flag, [branch ? 'b' : 'd'], branch: branch, path: path)
415
416
  end
416
417
  when :url
417
418
  format_desc action, flag, 'path,url,opts*'
@@ -498,7 +499,7 @@ module Squared
498
499
  remote = choice_remote
499
500
  end
500
501
  ret = tag(flag, refs: [name], message: message, commit: commit, remote: remote)
501
- print_success if success?(ret) && !remote
502
+ print_success if success?(ret, !remote)
502
503
  end
503
504
  end
504
505
  when 'stash'
@@ -640,7 +641,7 @@ module Squared
640
641
  task flag, [:commit] do |_, args|
641
642
  commit = commithead args.commit
642
643
  unless commit
643
- commit, merge = choice_commit(values: ['Merge? [y|N]'])
644
+ commit, merge = choice_commit(values: ['Merge? [y/N]'])
644
645
  merge = merge&.upcase == 'Y'
645
646
  end
646
647
  checkout(flag, commit: commit, merge: merge)
@@ -721,7 +722,7 @@ module Squared
721
722
  task flag, [:name, :commit] do |_, args|
722
723
  branch = param_guard(action, flag, args: args, key: :name)
723
724
  commit = commithead args.commit
724
- commit, track = choice_commit(values: ['Track? [Y|n]'], force: false) if commit == ':'
725
+ commit, track = choice_commit(values: ['Track? [Y/n]'], force: false) if commit == ':'
725
726
  switch(flag, branch: branch, commit: commit, track: track)
726
727
  end
727
728
  when :detach
@@ -1476,7 +1477,9 @@ module Squared
1476
1477
  source op
1477
1478
  cached = git_spawn 'diff --cached --name-only --no-color'
1478
1479
  if amend || !cached.empty? || dryrun?
1479
- puts cached if adding.empty? && !cached.empty? && banner?
1480
+ if adding.empty? && !cached.empty? && banner?
1481
+ puts(cached.lines.map! { |val| "cached #{shell_quote(val.chomp)}" })
1482
+ end
1480
1483
  source co
1481
1484
  source pu
1482
1485
  elsif banner?
@@ -1642,21 +1645,19 @@ module Squared
1642
1645
  source
1643
1646
  end
1644
1647
 
1645
- def submodule(flag, opts = [], path: nil, url: nil)
1648
+ def submodule(flag, opts = [], branch: nil, path: nil, url: nil)
1646
1649
  cmd, opts = git_session('submodule', opts: opts)
1647
1650
  op = OptionPartition.new(opts, OPT_GIT[:submodule].fetch(flag, []), cmd, project: self)
1648
1651
  case flag
1649
1652
  when :branch, :url
1650
1653
  op.adjoin("set-#{flag}")
1651
- op << '--'
1652
- op.add_path(path) if path
1653
- op.add_quote(url) if url
1654
+ op.add_quote(branch, '--', path, url)
1654
1655
  else
1655
1656
  op.adjoin(flag)
1656
1657
  op << '--recursive' if option('recursive', 'r')
1657
1658
  op.splice(path: true)
1658
1659
  end
1659
- source
1660
+ print_success if success?(source, flag == :branch)
1660
1661
  end
1661
1662
 
1662
1663
  def restore(flag, opts = [], commit: nil, files: nil)
@@ -374,7 +374,7 @@ module Squared
374
374
  target.mkpath
375
375
  subdir << target.to_s
376
376
  end
377
- FileUtils.cp(basepath(s), dest, verbose: verbose.is_a?(Numeric) && verbose > 0)
377
+ FileUtils.cp(basepath(s), dest, verbose: verbosetype > 0)
378
378
  rescue StandardError => e
379
379
  print_error e
380
380
  errors += 1
@@ -416,7 +416,7 @@ module Squared
416
416
  end
417
417
  target.each do |src, to|
418
418
  glob.each { |val| log.info "cp #{from + val} #{to}" }
419
- copy_dir(src, to, glob, create: create, link: link, force: force, pass: pass, verbose: verbose)
419
+ copy_dir(src, to, glob, create: create, link: link, force: force, pass: pass, verbose: verbosetype > 0)
420
420
  rescue StandardError => e
421
421
  on_error e, :copy
422
422
  end
@@ -487,7 +487,7 @@ module Squared
487
487
 
488
488
  def outdated(flag = nil, opts = [], sync: invoked_sync?('outdated', flag))
489
489
  dryrun = opts.include?('dry-run') || opts.include?('d')
490
- if pnpm? && read_packagemanager(version: '7.15', update: true)
490
+ if pnpm?
491
491
  cmd = session 'pnpm', 'outdated'
492
492
  dryrun ||= dryrun?('pnpm')
493
493
  else
@@ -312,7 +312,7 @@ module Squared
312
312
  c = glob[i] || glob.first
313
313
  log.info "cp #{a + c} #{b}"
314
314
  begin
315
- copy_dir(a, b, c, pass: pass, verbose: verbose)
315
+ copy_dir(a, b, c, pass: pass, verbose: verbosetype > 0)
316
316
  rescue StandardError => e
317
317
  on_error e, :copy
318
318
  end
@@ -528,7 +528,9 @@ module Squared
528
528
  if @asdf
529
529
  cmd = 'asdf'
530
530
  ver = '.tool-versions'
531
- `asdf current #{@asdf.first}`[/\A\S+\s+\S+/, 0].sub(/\s+/, ' ')
531
+ opt = [@asdf.first]
532
+ opt.unshift('--no-header') unless @@asdf[1] == 15
533
+ `asdf current #{opt.join(' ')}`[/^\S+\s+\S+/, 0].sub(/\s+/, ' ')
532
534
  else
533
535
  ver = nil
534
536
  `ruby --version`
@@ -10,9 +10,10 @@ module Squared
10
10
  include Common::Shell
11
11
  extend Forwardable
12
12
 
13
+ OPT_NAME = /\A(?:(--)|-)((?(1)[A-Za-z\d]+|[A-Za-z\d]))\z/
13
14
  OPT_VALUE = /\A-{0,2}([^= ]+)(?: *= *| +)(.+)\z/
14
15
  OPT_SINGLE = /\A-([A-Za-z\d])(.+)\z/
15
- private_constant :OPT_VALUE, :OPT_SINGLE
16
+ private_constant :OPT_NAME, :OPT_VALUE, :OPT_SINGLE
16
17
 
17
18
  class << self
18
19
  include Common::Format
@@ -70,8 +71,8 @@ module Squared
70
71
  def strip(val)
71
72
  return [] unless val
72
73
 
73
- val = shell_split(val) if val.is_a?(String)
74
- val.map { |s| s.sub(OPT_SINGLE, '\1=\2').sub(OPT_VALUE, '\1=\2') }.reject(&:empty?)
74
+ val = shell_split val if val.is_a?(String)
75
+ val.map { |s| s.sub(OPT_SINGLE, '\1=\2').sub(OPT_VALUE, '\1=\2').sub(OPT_NAME, '\2') }.reject(&:empty?)
75
76
  end
76
77
 
77
78
  def select(list, bare: true, no: true, single: false, double: false)
@@ -247,9 +248,9 @@ module Squared
247
248
  add quote_option(key, val, double: qq.include?(key), merge: merge)
248
249
  elsif p.include?(key)
249
250
  if val.match?(/\A(["']).+\1\z/)
250
- add shell_option(key, val, escape: false, merge: merge, sep: sep)
251
+ add shell_option(key, val, escape: false, merge: merge)
251
252
  elsif path
252
- add quote_option(key, path + val, merge: merge, sep: sep)
253
+ add quote_option(key, path + val, merge: merge)
253
254
  else
254
255
  push opt
255
256
  end
@@ -414,7 +415,7 @@ module Squared
414
415
  end
415
416
 
416
417
  def add_quote(*args, **kwargs)
417
- merge(args.map! { |val| shell_quote(val, **kwargs) })
418
+ merge(args.compact.map! { |val| val == '--' ? val : shell_quote(val, **kwargs) })
418
419
  self
419
420
  end
420
421
 
@@ -132,19 +132,20 @@ module Squared
132
132
  task 'all' do |_, args|
133
133
  stage ||= 'all'
134
134
  ns['sync'].invoke(*args.to_a)
135
- next if env('REPO_STAGE', equals: '1')
135
+ next if (stage = env('REPO_STAGE')) == '1'
136
136
 
137
137
  @project.select do |_, proj|
138
138
  next unless proj.enabled?(proj.workspace.baseref)
139
139
 
140
140
  proj.depend(sync: true) if proj.depend?
141
- next if env('REPO_STAGE', equals: '2')
141
+ next if stage == '2'
142
142
 
143
143
  proj.build?
144
144
  end
145
145
  .each_value do |proj|
146
146
  proj.build(sync: true)
147
- next unless proj.dev? && proj.copy? && !env('REPO_STAGE', equals: '3')
147
+ next if stage == '3'
148
+ next unless proj.copy? && (proj.dev? || stage == '4')
148
149
 
149
150
  if (ws = proj.workspace).task_defined?(target = task_join(proj.name, 'copy'))
150
151
  task_invoke(target, **ws.invokeargs)
@@ -11,6 +11,26 @@ module Squared
11
11
  def hashlist
12
12
  Hash.new { |data, key| data[key] = [] }
13
13
  end
14
+
15
+ def hashdup(data, pass: [])
16
+ ret = {}
17
+ data.each do |key, val|
18
+ ret[key] = case val
19
+ when Hash
20
+ if pass.include?(val)
21
+ val
22
+ else
23
+ pass << val
24
+ hashdup(val, pass: pass)
25
+ end
26
+ when Proc, Method
27
+ val
28
+ else
29
+ val.dup
30
+ end
31
+ end
32
+ ret
33
+ end
14
34
  end
15
35
  end
16
36
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squared
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.10
4
+ version: 0.5.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2025-10-18 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: rake
@@ -110,6 +111,7 @@ metadata:
110
111
  homepage_uri: https://github.com/anpham6/squared-ruby
111
112
  source_code_uri: https://github.com/anpham6/squared-ruby
112
113
  documentation_uri: https://squared.readthedocs.io
114
+ post_install_message:
113
115
  rdoc_options: []
114
116
  require_paths:
115
117
  - lib
@@ -124,7 +126,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
126
  - !ruby/object:Gem::Version
125
127
  version: '0'
126
128
  requirements: []
127
- rubygems_version: 3.7.2
129
+ rubygems_version: 3.2.33
130
+ signing_key:
128
131
  specification_version: 4
129
132
  summary: Rake task generator for managing multi-language workspaces.
130
133
  test_files: []