squared 0.4.25 → 0.4.26

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: 11a03c7d13bf0170f8b60953148792df626cf1c1edb02f7a1da9c46a4668fc1d
4
- data.tar.gz: ee42ffc6ac7b056604d9bb8ad81041dcd7787cb6d883b253f5390e7e94addc99
3
+ metadata.gz: 31cca2889400b4e4b51df7249ac426d782a9905cc69e731d0766ef1012002651
4
+ data.tar.gz: 4353d4d765dc14916e6db6c9605cc0b02fe48b353adc0ed274c08f01e0cc6f25
5
5
  SHA512:
6
- metadata.gz: 23cf6af69c98270efe9894f77e646c6006e34652aae843cc621fd6248324efece67b90bd60ea107f28c7a38b522885984f8f0e5e962dc5dd67c6d52ae522ac05
7
- data.tar.gz: 3cd04987351a9a9f98c878ab93307270ea7fa84d93207d361455ec008dc757ad98b258b2c098280ae1ae22aee78b90b179df9b654d9f01594b2c1198d02f4b0b
6
+ metadata.gz: 6fda0932de949193edfc82bb533c3b21b39624b2d1d8fc3b1762b0c8e93ce47807e9a34c8b378896d6f4f92c18d06ae82b217dfd42539667cb0df3de5d98cd5c
7
+ data.tar.gz: 411bba4daeb35c641b67306bba13502a78cab65c09e94d3a5fcef0f7ad213f5a8a75886b641a32d4e1dce83b6c697784ca438d4c570a30dd3d331ae8b25541c0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.26] - 2025-10-31
4
+
5
+ ### Added
6
+
7
+ - Docker command options were updated to 28.5.
8
+
9
+ ### Changed
10
+
11
+ - Node package manager does not override package.json with NODE_INSTALL.
12
+ - Node workspaces can specify more than one package manager through NODE_INSTALL.
13
+
14
+ ### Fixed
15
+
16
+ - Node command add did not provide optional save argument.
17
+ - Python command outdated did not detect synchronous output.
18
+ - Node command outdated auto-commit was completely dysfunctional.
19
+ - Project workspaces caused a complete meltdown on TruffleRuby.
20
+ - Project build initialization global flag was always incoherent.
21
+ - Project base setters did not accept direct values.
22
+ - Project base global graph tasks are not definable by a sub-project.
23
+
3
24
  ## [0.4.25] - 2025-10-18
4
25
 
5
26
  ### Fixed
@@ -1043,6 +1064,7 @@
1043
1064
 
1044
1065
  - Changelog was created.
1045
1066
 
1067
+ [0.4.26]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.26
1046
1068
  [0.4.25]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.25
1047
1069
  [0.4.24]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.24
1048
1070
  [0.4.23]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.23
data/README.md CHANGED
@@ -686,7 +686,7 @@ GIT_AUTOSTASH_${NAME}=0 # rebase (project only)
686
686
 
687
687
  ### Docker
688
688
 
689
- * Version: 28.3
689
+ * Version: [28.5](https://docs.docker.com/engine/release-notes/28)
690
690
 
691
691
  ```sh
692
692
  DOCKER_OPTIONS=q,no-cache # all
@@ -108,7 +108,7 @@ module Squared
108
108
  ret = wrap.call(ret, code) unless code.empty?
109
109
  return ret unless data
110
110
 
111
- out = ''.dup
111
+ out = +''
112
112
  data.to_a.each_with_index do |group, i|
113
113
  next if i == 0
114
114
 
@@ -179,7 +179,7 @@ module Squared
179
179
  if level.is_a?(::Numeric)
180
180
  if append && respond_to?(:log)
181
181
  (log rescue nil).tap do |ref|
182
- ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(Logger)
182
+ ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(::Logger)
183
183
  end
184
184
  end
185
185
  return false if !pass && level < ARG[:LEVEL]
@@ -199,7 +199,7 @@ module Squared
199
199
  def log_console(*args, pipe: 1)
200
200
  return if args.first == false && args.size == 1
201
201
 
202
- if pipe.is_a?(Pathname)
202
+ if pipe.is_a?(::Pathname)
203
203
  begin
204
204
  File.open(pipe, 'a') do |f|
205
205
  br = File::SEPARATOR == '\\' ? "\r\n" : "\n"
@@ -233,7 +233,7 @@ module Squared
233
233
  lines = val.map(&:to_s)
234
234
  else
235
235
  lines = val.to_s.lines(chomp: true)
236
- lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(StandardError))
236
+ lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(::StandardError))
237
237
  end
238
238
  n = cols || max.call(lines)
239
239
  if $stdout.tty?
@@ -47,11 +47,11 @@ module Squared
47
47
  end
48
48
  max = items.size
49
49
  raise_error 'empty selection list' if max == 0
50
- min = [min, max].min
50
+ min = grep ? 1 : [min, max].min
51
51
  if auto
52
- msg = "#{msg}: [1-#{max}#{if multiple
53
- "|,#{multiple.is_a?(Numeric) ? "{#{multiple}}" : ''}"
54
- end}] "
52
+ msg = "#{msg + (force ? ':' : '?')} [#{min}-#{max}#{if (n = multiple)
53
+ "|,#{n.is_a?(::Numeric) ? "{#{n}}" : ''}"
54
+ end}] "
55
55
  end
56
56
  end
57
57
  valid = ->(s) { s.match?(/^-?\d+$/) && s.to_i.between?(min, max) }
@@ -63,10 +63,7 @@ module Squared
63
63
  a = ch.split(/\s*,\s*/)
64
64
  b = a.select { |s| valid.call(s) }.map!(&:to_i).sort
65
65
  next unless a.size == b.size
66
- return b unless items
67
- next if multiple.is_a?(::Numeric) && multiple != b.size
68
-
69
- return b.map! { |i| items[i - 1] }
66
+ return items ? b.map! { |i| items[i - 1] } : b unless multiple.is_a?(::Numeric) && multiple != b.size
70
67
  elsif valid.call(ch)
71
68
  return items ? items[ch.to_i - 1] : ch.to_i
72
69
  end
@@ -97,18 +94,18 @@ module Squared
97
94
  elsif block_given?
98
95
  Readline.readmultiline(msg, history, &blk)
99
96
  else
100
- Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val) } }
97
+ Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val.to_s) } }
101
98
  end
102
99
  end
103
100
  case force
104
101
  when ::TrueClass, ::FalseClass
105
102
  msg = "#{msg} %s " % if multiline
106
- multiline.is_a?(::Enumerable) ? "{#{multiline.join('|')}}" : multiline
103
+ multiline.is_a?(::Enumerable) ? "{#{multiline.to_a.join('|')}}" : multiline
107
104
  else
108
105
  "(#{force ? 'required' : 'optional'}):"
109
106
  end
110
107
  ret = (prompt.call || '').strip
111
- multiline.each { |val| break if ret.delete_suffix!(val) } if multiline.is_a?(::Enumerable)
108
+ multiline.each { |val| break if ret.delete_suffix!(val.to_s) } if multiline.is_a?(::Enumerable)
112
109
  exit 1 if force && ret.empty?
113
110
  ret
114
111
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.4.25'
4
+ VERSION = '0.4.26'
5
5
  end
@@ -147,13 +147,12 @@ module Squared
147
147
  def build(parallel: [], pass: nil, **kwargs)
148
148
  return self unless enabled? && !@closed
149
149
 
150
- if kwargs[:pattern].is_a?(Array)
151
- kwargs[:parallel] = parallel.map(&:to_s)
152
- else
153
- kwargs[:pattern] = []
154
- kwargs[:parallel] = parallel.reject { |val| val.is_a?(Regexp) && (kwargs[:pattern] << val) }
155
- .map(&:to_s)
156
- end
150
+ kwargs[:parallel] = if kwargs[:pattern].is_a?(Array)
151
+ parallel.map(&:to_s)
152
+ else
153
+ kwargs[:pattern] = []
154
+ parallel.reject { |val| kwargs[:pattern] << val if val.is_a?(Regexp) }.map!(&:to_s)
155
+ end
157
156
  @pass[:pattern].concat(pass.map { |val| val.is_a?(Regexp) ? val : val.to_s }) if pass
158
157
  @project.each_value do |proj|
159
158
  if proj.enabled?
@@ -617,9 +616,7 @@ module Squared
617
616
  end
618
617
 
619
618
  def home?
620
- return false unless (proj = find(home))
621
-
622
- proj.enabled?
619
+ !!find(home)&.enabled?
623
620
  end
624
621
 
625
622
  def windows?
@@ -74,6 +74,7 @@ module Squared
74
74
 
75
75
  attr_reader :name, :project, :workspace, :path, :theme, :group, :parent, :dependfile,
76
76
  :exception, :pipe, :verbose
77
+ attr_accessor :global
77
78
 
78
79
  def initialize(workspace, path, name, *, group: nil, first: {}, last: {}, error: {}, common: ARG[:COMMON],
79
80
  **kwargs)
@@ -91,9 +92,14 @@ module Squared
91
92
  @clean = kwargs[:clean]
92
93
  @release = kwargs[:release]
93
94
  self.version = kwargs[:version]
94
- self.exception = kwargs[:exception]
95
- self.pipe = kwargs[:pipe]
96
- self.verbose = kwargs[:verbose]
95
+ self.exception = env_bool(kwargs[:exception], workspace.exception, strict: true)
96
+ self.pipe = env_pipe(kwargs[:pipe], workspace.pipe, strict: true)
97
+ self.verbose = case (val = env('VERBOSE', kwargs[:verbose]))
98
+ when String
99
+ env_bool(val, workspace.verbose, strict: true, index: true)
100
+ else
101
+ val.nil? ? workspace.verbose : val
102
+ end
97
103
  @output = []
98
104
  @ref = []
99
105
  @children = []
@@ -138,8 +144,10 @@ module Squared
138
144
  data = @workspace.script_find(*@ref, @group)
139
145
  if @output[0].nil?
140
146
  if (scr = data[:script])
141
- @global = true
142
- script_set(scr, args: data.fetch(:args, kwargs[:args]), prod: kwargs[:prod])
147
+ unless kwargs[:script] == false
148
+ @global = true
149
+ script_set(scr, args: data.fetch(:args, kwargs[:args]), prod: kwargs[:prod])
150
+ end
143
151
  elsif (run = data[:run])
144
152
  @global = true
145
153
  run_set run
@@ -162,7 +170,6 @@ module Squared
162
170
  @global = true
163
171
  run_set data[:run]
164
172
  end
165
- @global = true
166
173
  end
167
174
 
168
175
  def initialize_events(ref, **)
@@ -279,21 +286,29 @@ module Squared
279
286
  end
280
287
 
281
288
  def exception=(val)
282
- @exception = env_bool(val, workspace.exception, strict: true)
289
+ @exception = case val
290
+ when Numeric, TrueClass, FalseClass
291
+ val
292
+ else
293
+ workspace.exception
294
+ end
283
295
  end
284
296
 
285
297
  def pipe=(val)
286
- @pipe = env_pipe(val, workspace.pipe, strict: true)
298
+ @pipe = case val
299
+ when Numeric, Pathname
300
+ val
301
+ else
302
+ workspace.pipe
303
+ end
287
304
  end
288
305
 
289
306
  def verbose=(val)
290
- @verbose = case (val = env('VERBOSE', val))
291
- when NilClass
292
- workspace.verbose
293
- when String
294
- env_bool(val, workspace.verbose, strict: true, index: true)
295
- else
307
+ @verbose = case val
308
+ when Numeric, TrueClass, FalseClass
296
309
  val
310
+ else
311
+ workspace.verbose
297
312
  end
298
313
  end
299
314
 
@@ -323,13 +338,8 @@ module Squared
323
338
  else
324
339
  out, done = graph(args, out: [])
325
340
  out.map! do |val|
326
- done.each_with_index do |proj, i|
327
- next unless val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/)
328
-
329
- val += " (#{i.succ})"
330
- break
331
- end
332
- val
341
+ n = done.index { |proj| val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/) }
342
+ n ? "#{val} (#{n.succ})" : val
333
343
  end
334
344
  emphasize(out, title: path, right: true, border: borderstyle, sub: [
335
345
  { pat: /\A(#{Regexp.escape(path.to_s)})(.*)\z/, styles: theme[:header] },
@@ -385,35 +395,33 @@ module Squared
385
395
  end
386
396
 
387
397
  def add(path, name = nil, **kwargs, &blk)
388
- if path.is_a?(String) && (seg = path[%r{\A(.+)[\\/]\*+\z}, 1])
389
- return self unless checkdir?(path = basepath(seg))
398
+ if path.is_a?(String) && path =~ %r{\A(.+)[\\/]\*+\z}
399
+ return self unless checkdir?(path = basepath($1))
390
400
 
391
401
  path = path.children.select { |val| checkdir?(val) }
392
402
  end
393
403
  if path.is_a?(Array)
394
- name = @name if name == true
404
+ name = self.name if name == true
395
405
  path.each { |val| add(val, name && task_join(name, File.basename(val)), **kwargs, &blk) }
396
- return self
397
- elsif !projectpath?(path = basepath(path)) || !checkdir?(path)
398
- return self
399
- end
400
- kwargs = hashdup(@withargs).update(kwargs) if @withargs
401
- kwargs[:group] = group if group && !kwargs.key?(:group)
402
- kwargs[:ref] = ref unless kwargs.key?(:ref)
403
- parent = self
404
- proj = nil
405
- name = case name
406
- when String, Symbol
407
- name.to_s
408
- else
409
- path.basename
410
- end
411
- workspace.add(path, name, **kwargs) do
412
- __send__ :parent_set, parent
413
- proj = self
414
- instance_eval(&blk) if block_given?
415
- end
416
- @children << proj
406
+ elsif projectpath?(path = basepath(path)) && checkdir?(path)
407
+ kwargs = hashdup(@withargs).update(kwargs) if @withargs
408
+ kwargs[:group] = group if group && !kwargs.key?(:group)
409
+ kwargs[:ref] = ref unless kwargs.key?(:ref)
410
+ parent = self
411
+ proj = nil
412
+ name = case name
413
+ when String, Symbol
414
+ name.to_s
415
+ else
416
+ path.basename
417
+ end
418
+ workspace.add(path, name, **kwargs) do
419
+ __send__ :parent_set, parent
420
+ proj = self
421
+ instance_eval(&blk) if block_given?
422
+ end
423
+ @children << proj
424
+ end
417
425
  self
418
426
  end
419
427
 
@@ -423,13 +431,13 @@ module Squared
423
431
  end
424
432
 
425
433
  def inject(obj, *args, **kwargs, &blk)
426
- return self unless enabled?
427
-
428
- out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
429
- if !out
430
- print_error('link not compatible', subject: obj, hint: name)
431
- elsif out.respond_to?(:build)
432
- out.build
434
+ if enabled?
435
+ out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
436
+ if !out
437
+ print_error('link not compatible', subject: obj, hint: name)
438
+ elsif out.respond_to?(:build)
439
+ out.build
440
+ end
433
441
  end
434
442
  self
435
443
  end
@@ -513,7 +521,7 @@ module Squared
513
521
  next if @@graph[:_].include?(proj)
514
522
 
515
523
  if (val = ENV["PREREQS_#{proj.instance_variable_get(:@envname)}"] || ENV["PREREQS_#{proj.ref.upcase}"])
516
- val.split(/\s*,\s*/).each do |meth|
524
+ split_escape(val).each do |meth|
517
525
  if proj.respond_to?(meth.to_sym)
518
526
  begin
519
527
  proj.__send__(meth, sync: sync)
@@ -572,7 +580,7 @@ module Squared
572
580
  begin
573
581
  @clean.each { |cmd, opts| build(cmd.to_s, opts, sync: sync) }
574
582
  rescue StandardError => e
575
- on_error e, from
583
+ on_error e, :clean
576
584
  end
577
585
  else
578
586
  if @clean.is_a?(Enumerable) && !series?(@clean)
@@ -683,6 +691,8 @@ module Squared
683
691
  ext = 'tgz'
684
692
  when 'application/x-xz'
685
693
  ext = 'txz'
694
+ when 'application/x-7z-compressed'
695
+ ext = '7z'
686
696
  end
687
697
  end
688
698
  break uri = url if data
@@ -717,7 +727,7 @@ module Squared
717
727
  case ext
718
728
  when 'zip', 'aar'
719
729
  session 'unzip', shell_quote(file), quote_option('d', target)
720
- when 'tar', 'tgz', 'tar.gz', 'tar.xz', 'gz', 'xz'
730
+ when 'tar', 'tgz', 'txz', 'tar.gz', 'tar.xz', 'gz', 'xz'
721
731
  flags = +(verbose ? 'v' : '')
722
732
  if ext.end_with?('gz')
723
733
  flags += 'z'
@@ -1072,6 +1082,7 @@ module Squared
1072
1082
  def graph_branch(target, data, tasks = nil, out = nil, sync: true, pass: [], done: [], depth: 0,
1073
1083
  single: false, last: false, context: nil)
1074
1084
  tag = ->(proj) { "#{proj.name}#{SEM_VER.match?(proj.version) ? "@#{proj.version}" : ''}" }
1085
+ script = ->(proj) { workspace.script_get(:graph, group: proj.group, ref: proj.allref)&.fetch(:graph, nil) }
1075
1086
  check = ->(deps) { deps.reject { |val| done.include?(val) } }
1076
1087
  dedupe = lambda do |name|
1077
1088
  next [] unless (ret = data[name])
@@ -1122,10 +1133,7 @@ module Squared
1122
1133
  single: single, last: j == true, context: target)
1123
1134
  end
1124
1135
  if !out
1125
- if !tasks && (script = workspace.script_get(:graph, group: proj.group, ref: proj.allref))
1126
- tasks = script[:graph]
1127
- end
1128
- (tasks || (dev? ? ['build', 'copy'] : ['depend', 'build'])).each do |meth|
1136
+ (tasks || (subtasks = script.call(proj)) || (dev? ? %w[build copy] : %w[depend build])).each do |meth|
1129
1137
  next if pass.include?(meth)
1130
1138
 
1131
1139
  if workspace.task_defined?(cmd = task_join(proj.name, meth))
@@ -1136,7 +1144,7 @@ module Squared
1136
1144
  end
1137
1145
  run(cmd, sync: false, banner: false)
1138
1146
  ENV.delete(key) if key
1139
- elsif proj.has?(meth, tasks ? nil : workspace.baseref)
1147
+ elsif proj.has?(meth, tasks || subtasks ? nil : workspace.baseref)
1140
1148
  proj.__send__(meth.to_sym, sync: sync)
1141
1149
  end
1142
1150
  end
@@ -1322,7 +1330,7 @@ module Squared
1322
1330
  sub&.each { |h| s = sub_style(s, **h) }
1323
1331
  s
1324
1332
  end
1325
- ret = [sub_style(ARG[:BORDER][1] * n, styles: border), *lines]
1333
+ ret = [sub_style(ARG[:BORDER][1] * n, styles: border)].concat(lines)
1326
1334
  ret.reverse! if reverse
1327
1335
  ret.join("\n")
1328
1336
  end
@@ -1424,7 +1432,7 @@ module Squared
1424
1432
  else
1425
1433
  pat = /\A(\s*\d+\.)(.+)\z/
1426
1434
  unless grep.empty?
1427
- footer = "#{out.size} found"
1435
+ footer = "#{out.size} found "
1428
1436
  sub << { pat: /\A(\d+)( .+)\z/, styles: theme[:inline] }
1429
1437
  end
1430
1438
  end
@@ -1751,10 +1759,8 @@ module Squared
1751
1759
 
1752
1760
  def semcmp(val, other)
1753
1761
  return 0 if val == other
1754
-
1755
- a, b = [val, other].map! { |ver| ver.scan(SEM_VER) }
1756
- return -1 if b.empty?
1757
- return 1 if a.empty?
1762
+ return -1 if (b = other.scan(SEM_VER)).empty?
1763
+ return 1 if (a = val.scan(SEM_VER)).empty?
1758
1764
 
1759
1765
  a, b = [a.first, b.first].map! do |c|
1760
1766
  begin
@@ -2030,7 +2036,7 @@ module Squared
2030
2036
  if val.directory? && !val.empty?
2031
2037
  true
2032
2038
  else
2033
- log&.warn "directory \"#{val}\" (#{val.empty? ? 'empty' : 'not found'})"
2039
+ log&.warn "directory \"#{val}\" (#{val.directory? ? 'empty' : 'not found'})"
2034
2040
  false
2035
2041
  end
2036
2042
  end
@@ -13,7 +13,7 @@ module Squared
13
13
  buildx: {
14
14
  common: %w[builder=b D|debug],
15
15
  build: %w[add-host=q annotation=q attest=q build-arg=qq build-context=qq cache-from=q cache-to=q
16
- cgroup-parent=b ent=q iidfile=p label=q a-file=p network=b no-cache-filter=b o|output=q platform=b
16
+ cgroup-parent=b iidfile=p label=q a-file=p network=b no-cache-filter=b o|output=q platform=b
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
19
  shared: %w[check load no-cache pull push allow=q call=b? f|file=p metadata-file=p progress=b provenance=q
@@ -26,8 +26,8 @@ module Squared
26
26
  provenance=q sbom=q ssh=qq].freeze,
27
27
  exec: %w[d|detach privileged e|env=qq index=i T|no-TTY=b? user=e w|workdir=q].freeze,
28
28
  run: %w[build d|detach no-deps q|quiet quiet-build quiet-pull remove-orphans rm P|service-ports use-aliases
29
- cap-add=b cap-drop=b q e|env=qq env-from-file=p i|interactive=b? l|label=q name=b T|no-TTY=b?
30
- p|publish=e pull=b u|user=e v|volume=q w|workdir=q].freeze,
29
+ cap-add=b cap-drop=b entrypoint=q e|env=qq env-from-file=p i|interactive=b? l|label=q name=b
30
+ T|no-TTY=b? p|publish=q pull=b u|user=e v|volume=q w|workdir=q].freeze,
31
31
  up: %w[abort-on-container-exit abort-on-container-failure always-recreate-deps attach-dependencies build
32
32
  d|detach force-recreate menu no-build no-color no-deps no-log-prefix no-recreate no-start quiet-build
33
33
  quiet-pull remove-orphans V|renew-anon-volumes timestamps wait w|watch y|yes attach=b
@@ -36,25 +36,26 @@ module Squared
36
36
  }.freeze,
37
37
  container: {
38
38
  create: %w[init i|interactive no-healthcheck oom-kill-disable privileged P|publish-all q|quiet read-only
39
- rm runtime t|tty use-api-socket io-maxbandwidth=b io-maxiops=b add-host=q annotation=q a|attach=b
40
- blkio-weight=i blkio-weight-device=i cap-add=b cap-drop=b cgroup-parent=b cgroupns=b cidfile=p
41
- device=q device-cgroup-rule=q device-read-bps=q device-read-iops=q device-write-bps=q
42
- device-write-iops=q disable-content-trust=b? dns=e dns-option=e dns-search=e domainname=b
43
- entrypoint=q e|env=qq env-file=p expose=e gpus=q group-add=b health-cmd=q health-interval=b ip6=e
44
- ipc=b isolation=b kernel-memory=b l|label=q label-file=p link=b link-local-ip=b log-driver=b
45
- log-opt=q mac-address=e m|memory=b memory-reservation=b memory-swap=n memory-swappiness=n
46
- mount=qq name=b network=b network-alias=b oom-score-adj=b pid=b pids-limit=n platform=b
47
- p|publish=e pull=b restart=b runtime=b security-opt=q shm-size=b stop-signal=b stop-timeout=i
48
- storage-opt=q sysctl=q tmpfs=q ulimit=q u|user=b userns=b uts=b v|volume=q volume-driver=b
49
- volumes-from=b w|workdir=q].freeze,
50
- run: %w[d|detach detach-keys=q sig-proxy=b?].freeze,
39
+ rm t|tty use-api-socket add-host=q annotation=q a|attach=b blkio-weight=i blkio-weight-device=i
40
+ cap-add=b cap-drop=b cgroup-parent=b cgroupns=b cidfile=p device=q device-cgroup-rule=q
41
+ device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q
42
+ disable-content-trust=b? dns=q dns-option=q dns-search=q domainname=b entrypoint=q e|env=qq
43
+ env-file=p expose=q gpus=q group-add=b health-cmd=q health-interval=b health-retries=i
44
+ health-start-interval=q health-start-period=q health-timeout=q io-maxbandwidth=b io-maxiops=b
45
+ ip=b ip6=q ipc=b isolation=b kernel-memory=b l|label=q label-file=q link=b link-local-ip=q
46
+ log-driver=b log-opt=q mac-address=q m|memory=b memory-reservation=b memory-swap=n
47
+ memory-swappiness=n mount=qq name=b network=b network-alias=b oom-score-adj=b pid=b pids-limit=n
48
+ platform=b p|publish=q pull=b restart=b runtime=b security-opt=q shm-size=b stop-signal=b
49
+ stop-timeout=i storage-opt=q sysctl=q tmpfs=q ulimit=q u|user=b userns=b uts=b v|volume=q
50
+ volume-driver=b volumes-from=b w|workdir=q].freeze,
51
+ run: %w[d|detach detach-keys=q hostname=q sig-proxy=b?].freeze,
51
52
  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
52
53
  cpuset-cpus=b cpuset-mems=b m|memory=b memory-reservation=b memory-swap=b pids-limit=n
53
54
  restart=q].freeze,
54
55
  exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p user=e
55
56
  w|workdir=q].freeze,
56
57
  commit: %w[a|author=q c|change=q m|message=q pause=b?].freeze,
57
- inspect: %w[s|size f|format=q].freeze,
58
+ inspect: %w[s|size f|format=q type=b].freeze,
58
59
  start: %w[a|attach i|interactive detach-keys=q].freeze,
59
60
  stop: %w[s|signal=b t|time=i t|timeout=i].freeze,
60
61
  restart: %w[s|signal=b t|time=i t|timeout=i].freeze,
@@ -68,7 +69,7 @@ module Squared
68
69
  save: %w[o|output=p platform=b].freeze
69
70
  }.freeze,
70
71
  network: {
71
- connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=b link=b link-local-ip=b].freeze,
72
+ connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=q link=b link-local-ip=q].freeze,
72
73
  disconnect: %w[f|force].freeze
73
74
  }.freeze
74
75
  }.freeze
@@ -630,13 +631,14 @@ module Squared
630
631
  when 2, 4
631
632
  return
632
633
  when 3
633
- return unless COMPOSEFILE.map { |val| basepath(val) }.select(&:exist?).size > 1
634
+ return unless COMPOSEFILE.select { |val| basepath(val).exist? }.size > 1
634
635
  end
635
636
  end
636
637
  files = Array(@file).map { |val| quote_option('file', basepath(val)) }
637
638
  if target.is_a?(Set)
638
639
  opts = target.to_a.insert(index, *files)
639
- target.clear.merge(opts)
640
+ target.clear
641
+ .merge(opts)
640
642
  else
641
643
  target.insert(index, *files)
642
644
  end
@@ -1549,7 +1549,7 @@ module Squared
1549
1549
  append_value list
1550
1550
  remote = nil
1551
1551
  when :move, :copy
1552
- s = "-#{flag.to_s[0]}"
1552
+ s = +"-#{flag.to_s[0]}"
1553
1553
  s.upcase! if option('force', 'f')
1554
1554
  cmd << s
1555
1555
  refs.compact.each { |val| cmd << shell_quote(val) }
@@ -1977,7 +1977,7 @@ module Squared
1977
1977
  when 'rebase'
1978
1978
  op << basic_option($1, $2) if VAL_GIT[:rebase][:value].include?($2)
1979
1979
  when 'shallow-since'
1980
- op.append?($1) { Date.parse($2)&.strftime('%F %T') }
1980
+ op.append?($1) { Date.parse($2).strftime('%F %T') }
1981
1981
  when 'recurse-submodules'
1982
1982
  op.append?($1, $2, type: :basic)
1983
1983
  when 'refspec'
@@ -129,13 +129,9 @@ module Squared
129
129
  when 'add'
130
130
  format_desc action, nil, 'save?=prod|dev|optional|peer,name+'
131
131
  task action, [:save] do |_, args|
132
- save = param_guard(action, 'save', args: args, key: :save)
133
- if save.start_with?('=')
134
- exact = true
135
- save = save[1..-1]
136
- end
137
- packages = case save
138
- when 'prod', 'dev', 'optional', 'peer'
132
+ packages = if args.save =~ /\A(=)?(prod|dev|optional|peer)\z/
133
+ exact = !$1.nil?
134
+ save = $2
139
135
  args.extras
140
136
  else
141
137
  save = 'prod'
@@ -426,19 +422,7 @@ module Squared
426
422
  workspace.rev_clear(name, sync: sync)
427
423
  return update if !flag && env('NODE_UPDATE')
428
424
 
429
- pnpm = pnpm?
430
- yarn = pnpm ? 0 : dependtype(:yarn)
431
- if @pm[:__] && !pnpm && yarn == 0
432
- case @pm[:__]
433
- when 'pnpm'
434
- pnpm = true
435
- when 'yarn'
436
- yarn = 1
437
- when 'berry'
438
- yarn = 2
439
- end
440
- end
441
- if yarn > 0
425
+ if (yarn = dependtype(:yarn)) > 0
442
426
  cmd = session 'yarn'
443
427
  if flag == :add
444
428
  cmd << 'add'
@@ -448,7 +432,7 @@ module Squared
448
432
  cmd << 'install'
449
433
  cmd << '--ignore-engines' if yarn == 1 && !option('ignore-engines', equals: '0')
450
434
  end
451
- elsif pnpm
435
+ elsif pnpm?
452
436
  cmd = session 'pnpm'
453
437
  if flag == :add
454
438
  cmd << 'add' << "--save-#{save}"
@@ -637,7 +621,7 @@ module Squared
637
621
  else
638
622
  footer.call(0, found.size)
639
623
  end
640
- commit(:add, refs: ['package.json'], pass: true)
624
+ commit(:add, ['package.json'], pass: true)
641
625
  end
642
626
  elsif !avail.empty?
643
627
  col1 = size_col.call(avail, 0) + 4
@@ -884,45 +868,32 @@ module Squared
884
868
 
885
869
  def yarn?
886
870
  (@pm[:yarn] ||= if rootpath('yarn.lock', ascend: dependext).exist?
887
- if (rc = rootpath('.yarnrc.yml', ascend: dependext)).exist?
888
- begin
889
- require 'yaml'
890
- doc = YAML.load_file(rc)
891
- doc.nodeLinker == 'node-modules' ? 2 : 3
892
- rescue StandardError => e
893
- log.debug e
894
- 3
895
- end
871
+ yarntype
872
+ elsif (ver = read_packagemanager || read_install)
873
+ if ver =~ /^yarn(?:@(\d)|$)/
874
+ $1 && $1.to_i > 1 ? yarntype : 1
896
875
  else
897
- 1
876
+ 0
898
877
  end
899
- elsif (ver = read_packagemanager || read_install)&.start_with?('yarn')
900
- ver == 'yarn' || ver.include?('@1') ? 1 : 3
901
878
  else
902
- 0
879
+ case @pm[:__]
880
+ when 'yarn'
881
+ 1
882
+ when 'berry'
883
+ yarntype
884
+ else
885
+ 0
886
+ end
903
887
  end) > 0
904
888
  end
905
889
 
906
890
  def pnpm?
907
891
  (@pm[:pnpm] ||= if rootpath('pnpm-lock.yaml', ascend: dependext).exist?
908
- begin
909
- require 'yaml'
910
- doc = YAML.load_file(basepath('node_modules/.modules.yaml', ascend: dependext))
911
- @pm[:_] = doc['packageManager']
912
- case doc['nodeLinker']
913
- when 'hoisted'
914
- 1
915
- when 'pnp'
916
- 3
917
- else
918
- 4
919
- end
920
- rescue StandardError => e
921
- log.debug e
922
- 4
923
- end
892
+ pnpmtype
893
+ elsif (ver = read_packagemanager || read_install)
894
+ ver.start_with?('pnpm') ? pnpmtype : 0
924
895
  else
925
- (read_packagemanager || read_install)&.start_with?('pnpm') ? 4 : 0
896
+ @pm[:__] == 'pnpm' ? pnpmtype : 0
926
897
  end) > 0
927
898
  end
928
899
 
@@ -972,14 +943,17 @@ module Squared
972
943
  private
973
944
 
974
945
  def read_packagemanager(key = nil, version: nil, update: false)
975
- if @pm[:_].nil? || update
946
+ if (key ? !@pm.key?(key) : @pm[:_].nil?) || update
976
947
  doc = JSON.parse(dependfile.read)
977
- @pm[:_] = (val = doc['packageManager']) ? val[0, val.index('+') || val.size] : false
978
- @pm[:name] = doc['name']
979
- @pm[:scripts] = doc['scripts']
980
- @pm[:version] = doc['version']
981
- @pm[:private] = doc['private']
982
- @pm[:workspaces] = doc['workspaces']
948
+ if @pm[:_].nil?
949
+ @pm[:_] = (val = doc['packageManager']) ? val[0, val.index('+') || val.size] : false
950
+ @pm[:name] = doc['name']
951
+ @pm[:scripts] = doc['scripts']
952
+ @pm[:version] = doc['version']
953
+ @pm[:private] = doc['private']
954
+ @pm[:workspaces] = doc['workspaces']
955
+ end
956
+ @pm[key] = doc[key.to_s] if key
983
957
  end
984
958
  rescue StandardError => e
985
959
  log.debug e
@@ -996,10 +970,67 @@ module Squared
996
970
  def read_install
997
971
  return unless (ret = env('NODE_INSTALL'))
998
972
 
999
- @pm[:_] ||= ret if ret.include?('@')
973
+ if ret.include?(',')
974
+ catch :found do
975
+ split_escape(ret).each do |val|
976
+ case val
977
+ when /^yarn/
978
+ next if yarntype(exist: true) == 0
979
+ when /^pnpm/
980
+ next if pnpmtype(exist: true) == 0
981
+ when /^npm/
982
+ nil
983
+ else
984
+ next
985
+ end
986
+ ret = val
987
+ throw :found
988
+ end
989
+ return
990
+ end
991
+ end
992
+ @pm[:_] ||= ret
1000
993
  ret
1001
994
  end
1002
995
 
996
+ def yarntype(exist: false)
997
+ if (rc = rootpath('.yarnrc.yml', ascend: dependext)).exist?
998
+ require 'yaml'
999
+ doc = YAML.load_file(rc)
1000
+ doc.nodeLinker == 'node-modules' ? 2 : 3
1001
+ elsif exist && !basepath('yarn.lock').exist?
1002
+ 0
1003
+ else
1004
+ 1
1005
+ end
1006
+ rescue StandardError => e
1007
+ return 0 if exist
1008
+
1009
+ log.debug e
1010
+ 3
1011
+ end
1012
+
1013
+ def pnpmtype(exist: false)
1014
+ require 'yaml'
1015
+ doc = YAML.load_file(basepath('node_modules/.modules.yaml', ascend: dependext))
1016
+ @pm['packageManager'] = doc['packageManager']
1017
+ case doc['nodeLinker']
1018
+ when 'hoisted'
1019
+ 1
1020
+ when 'pnp'
1021
+ 3
1022
+ else
1023
+ 4
1024
+ end
1025
+ rescue StandardError => e
1026
+ if exist
1027
+ %w[pnpm-lock.yaml pnpm-workspace.yaml].any? { |val| basepath(val).exist? } ? 4 : 0
1028
+ else
1029
+ log.debug e
1030
+ 4
1031
+ end
1032
+ end
1033
+
1003
1034
  def read_scripts
1004
1035
  ret = read_packagemanager(:scripts)
1005
1036
  ret.is_a?(Hash) ? ret.to_a : []
@@ -363,7 +363,7 @@ module Squared
363
363
  end
364
364
  end
365
365
 
366
- def outdated(flag = nil, opts = [], sync: invoked_sync?('outdated'))
366
+ def outdated(flag = nil, opts = [], sync: invoked_sync?('outdated', flag))
367
367
  cmd = pip_session 'list --outdated'
368
368
  append_global
369
369
  cmd = session_done cmd
@@ -886,7 +886,7 @@ module Squared
886
886
  pwd_set(pass: !opt.nil?) do
887
887
  out = `#{gem_output(opt, 'list --local -d', gemname)}`
888
888
  if out =~ /#{Regexp.escape(gemname)} \(([^)]+)\)/
889
- $1.split(/\s*,\s*/)
889
+ split_escape($1)
890
890
  .unshift(@version)
891
891
  .uniq
892
892
  .each do |val|
@@ -7,7 +7,7 @@ module Squared
7
7
  attr_accessor :line_width
8
8
 
9
9
  def max_width(lines)
10
- n = [lines.max_by(&:size).size, 80].max
10
+ n = [lines.empty? ? 0 : lines.max_by(&:size).size, 80].max
11
11
  [n, Rake.application.terminal_width].min
12
12
  end
13
13
  end
@@ -135,7 +135,7 @@ module Squared
135
135
  next if (stage = env('REPO_STAGE')) == '1'
136
136
 
137
137
  @project.select do |_, proj|
138
- next unless proj.enabled?(proj.workspace.baseref)
138
+ next unless proj.enabled?(proj.workspace.baseref) && proj.global
139
139
 
140
140
  proj.depend(sync: true) if proj.depend?
141
141
  next if stage == '2'
@@ -12,17 +12,12 @@ module Squared
12
12
  Hash.new { |data, key| data[key] = [] }
13
13
  end
14
14
 
15
- def hashdup(data, pass: [])
15
+ def hashdup(data, pass: {})
16
16
  ret = {}
17
17
  data.each do |key, val|
18
18
  ret[key] = case val
19
19
  when Hash
20
- if pass.include?(val)
21
- val
22
- else
23
- pass << val
24
- hashdup(val, pass: pass)
25
- end
20
+ pass[val] ||= hashdup(val, pass: pass)
26
21
  when Proc, Method
27
22
  val
28
23
  else
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squared
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.25
4
+ version: 0.4.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-10-18 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rake
@@ -112,7 +111,6 @@ metadata:
112
111
  homepage_uri: https://github.com/anpham6/squared-ruby
113
112
  source_code_uri: https://github.com/anpham6/squared-ruby
114
113
  documentation_uri: https://squared.readthedocs.io
115
- post_install_message:
116
114
  rdoc_options: []
117
115
  require_paths:
118
116
  - lib
@@ -127,8 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
125
  - !ruby/object:Gem::Version
128
126
  version: '0'
129
127
  requirements: []
130
- rubygems_version: 3.2.33
131
- signing_key:
128
+ rubygems_version: 3.7.2
132
129
  specification_version: 4
133
130
  summary: Rake task generator for managing multi-language workspaces.
134
131
  test_files: []