squared 0.9.0.pre1 → 0.9.0

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: ebde7859df22cda9eadd92f6bf88141ba9095a7528a8bba9e469333f1bb14370
4
- data.tar.gz: af5a6e759a021e46d76f4043dcea544b1a7e25dacaddad8389824782fbd1fe78
3
+ metadata.gz: 41f1d82942dcd7279ec182d1fc0bdc8f90ccc2e476860c6ca70bc89286417598
4
+ data.tar.gz: e6b7773f70fd0d2867fe13bdae57324dd6c90048c8bea3b27937738edf4df78c
5
5
  SHA512:
6
- metadata.gz: 3a00a2d227203bd36460e5a3242de692e7ae2822c1f2812a1a2ec271c4f5d8ffe32af050522e3e20e451920f57d8f5d7363933f7c5abdfb5cbe27e5989e7d41c
7
- data.tar.gz: 29ef41a9d546d00b4701bc763362a61426312b530b8d5378e60f309cd5469960cab206f969da791936f4da68f9d25772bbfa44dd759c90a5a500b8c504defb44
6
+ metadata.gz: cc02b93ac5fbfd34e23ff87cda66a3665fca3490c942e7a5942edb9ba6540eb6b95e1c87d8273444ec4bbac6d56841b7b3213295ce9ee856c15383794ecac97a
7
+ data.tar.gz: ee1c5b726339754ee878ff97cd9994983cbc5ca4822d2ffa25170c2f3512414966f367dcc5c4f0f2bc1eb8156667b88fcffc294ccbab1468c57ef465bb387243
data/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## [0.9.0] - 2026-10-12
4
4
 
5
5
  ### Added
6
6
 
@@ -18,6 +18,7 @@
18
18
  - Docker command network action rm is interactive.
19
19
  - Docker command container action rm is interactive.
20
20
  - Docker command run action entrypoint is interactive.
21
+ - Node command tsc accepts unfiltered arbitrary option flags.
21
22
 
22
23
  ### Changed
23
24
 
@@ -34,6 +35,8 @@
34
35
  - Repo sync option --fetch-submodules was renamed --recurse-submodules.
35
36
  - Ruby command script does not run code until it has passed validation.
36
37
  - Ruby gem io-console is used for default console size.
38
+ - Node program tsc boolean options support explicit values.
39
+ - Python program meson prefix options use local path resolution.
37
40
 
38
41
  ### Removed
39
42
 
@@ -42,6 +45,35 @@
42
45
  - Docker private method charname was replaced with subdomainname.
43
46
  - Git command show was relocated into command git action show.
44
47
 
48
+ ## [0.8.6] - 2026-10-01
49
+
50
+ ### Added
51
+
52
+ - Pip command options were updated to 26.2.
53
+ - Application method assign for appending project instance methods was created.
54
+
55
+ ### Fixed
56
+
57
+ - Bundle exec wrapper did not accept boolean values.
58
+ - RuboCop did not resolve config to project directory.
59
+
60
+ ## [0.7.13] - 2026-09-25
61
+
62
+ ### Fixed
63
+
64
+ - OptionPartition did not parse quoted option values.
65
+
66
+ ## [0.6.20] - 2026-09-25
67
+
68
+ ### Added
69
+
70
+ - Prompt choice optional selection can be bypassed with a single dash.
71
+ - OptionPartition can parse supplementary option flags for plain output.
72
+
73
+ ### Fixed
74
+
75
+ - Git interactive commit selection did not accept additional values.
76
+
45
77
  ## [0.8.5] - 2026-09-23
46
78
 
47
79
  ### Added
@@ -2166,12 +2198,15 @@
2166
2198
 
2167
2199
  - Changelog was created.
2168
2200
 
2201
+ [0.9.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.9.0
2202
+ [0.8.6]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.6
2169
2203
  [0.8.5]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.5
2170
2204
  [0.8.4]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.4
2171
2205
  [0.8.3]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.3
2172
2206
  [0.8.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.2
2173
2207
  [0.8.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.1
2174
2208
  [0.8.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.0
2209
+ [0.7.13]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.13
2175
2210
  [0.7.12]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.12
2176
2211
  [0.7.11]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.11
2177
2212
  [0.7.10]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.10
@@ -2185,6 +2220,7 @@
2185
2220
  [0.7.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.2
2186
2221
  [0.7.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.1
2187
2222
  [0.7.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.0
2223
+ [0.6.20]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.20
2188
2224
  [0.6.19]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.19
2189
2225
  [0.6.18]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.18
2190
2226
  [0.6.17]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.17
data/README.md CHANGED
@@ -43,11 +43,12 @@ Usage: sqd [options] [rake options] [global...] [:targets...] -- [rake targets..
43
43
 
44
44
  -s, --[no-]strict Do not run commands with invalid arguments
45
45
  --update Use update strategy for applicable commands
46
+ --parallel STR,PAT Run standard tasks with multi-task threads
46
47
  -F, --force [STR,STR] Enable force through ENV by application
47
48
  -y, --yes [STR,STR] Enable auto-approve through ENV by application
48
49
  -d, --dry-run Run commands without any modifying actions
49
50
 
50
- -S, --select PAGE:CHOICE Prompt menu selection pagination limits
51
+ -S, --select PAGE[:CHOICE] Prompt menu selection pagination display (e.g. 15:75)
51
52
 
52
53
  -p, --pipe 0|1|2 Set file descriptor for communication
53
54
  -o, --pipe-out FILE Write command data stream to a file
@@ -132,13 +133,13 @@ Workspace::Application
132
133
  apply :clean, ["build/sqd/"] # variable_set (alias)
133
134
  end
134
135
  .with(:docker, only: ["build", "compose"], hide: [:windows?]) do # When true hide entire group
135
- .add("squared", "docker", file: "Dockerfile", tag: "latest",
136
- registry: "localhost:5000", username: "squared", # compose publish => { oci: "oci://docker.io" }
137
- args: "--ssh=default",
138
- context: ".", # Optional
139
- client: { config: '/home/user/.docker', tls: true }, # global options
140
- secrets: ["id=github,env=GITHUB_TOKEN"],
141
- mounts: ["src=.,dst=/project,ro,bind-propagation=rshared"]) do
136
+ add("squared", "docker", file: "Dockerfile", tag: "latest",
137
+ registry: "localhost:5000", username: "squared", # compose publish => { oci: "oci://docker.io" }
138
+ args: "--ssh=default",
139
+ context: ".", # Optional
140
+ client: { config: '/home/user/.docker', tls: true }, # global options
141
+ secrets: ["id=github,env=GITHUB_TOKEN"],
142
+ mounts: ["src=.,dst=/project,ro,bind-propagation=rshared"]) do
142
143
  series(:clean) do # run | depend | doc | lint | test | copy | clean
143
144
  File.read(basepath("docker-bake.hcl"))
144
145
  .scan(/\btags\s+=\s+\["([^"]+)"\]/)
@@ -146,6 +147,15 @@ Workspace::Application
146
147
  end
147
148
  end
148
149
  end
150
+ .assign(:ruby) do # Add or override instance methods
151
+ def vmname(bin: false)
152
+ bin ? ['rbenv', '/usr/bin/rbenv'] : 'rbenv'
153
+ end
154
+
155
+ def copy?
156
+ false
157
+ end
158
+ end
149
159
  .pass("pull", group: "default") { test? || doc? } # rake pathname:pull optparse:pull
150
160
  .style("banner", 255.255) # 256 colors (fg | fg.bg | -0.bg)
151
161
  .build(default: "build", parallel: ["pull", "fetch", "rebase", "archive", "clean", /^outdated:/], pass: ["publish"]) do |workspace|
@@ -388,10 +398,10 @@ Workspace::Application
388
398
  run([nil, "build:dev", { "PATH" => "~/.bin" }, "--workspace", "--silent"]) # PATH="~/.bin" npm run build:dev --workspace -- --silent
389
399
  # OR
390
400
  run({
391
- script: "build:dev",
392
- env: { "PATH" => "~/.bin" },
393
- opts: "--workspace",
394
- args: "--silent"
401
+ script: "build:dev",
402
+ env: { "PATH" => "~/.bin" },
403
+ opts: "--workspace",
404
+ args: "--silent"
395
405
  })
396
406
 
397
407
  add("e-mc", "emc") do
data/exe/sqd CHANGED
@@ -1,8 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- $:.unshift(File.expand_path('../lib', __dir__)) if File.exist?(File.expand_path('../squared.gemspec', __dir__))
5
-
6
4
  require 'squared'
7
5
  require 'rake'
8
6
  require 'optparse'
@@ -103,6 +101,18 @@ class SqdParser < OptionParser
103
101
  ARGV[index] = ''
104
102
  end
105
103
  end
104
+ if options[:parallel]
105
+ pattern, parallel = options[:parallel].partition do |val|
106
+ next false if val.match?(%r{^[\w~`!@#%&\-=:;"'<>/]+$})
107
+
108
+ Regexp.new(val)
109
+ rescue RegexpError
110
+ false
111
+ end
112
+ session = Squared::Common::ARG
113
+ session[:APP][:build_pattern] = pattern.map { |pat| Regexp.new(pat) } unless pattern.empty?
114
+ session[:APP][:build_parallel] = parallel unless parallel.empty?
115
+ end
106
116
  ARGV.reject!(&:empty?)
107
117
  Rake.application.run(global.concat(ARGV))
108
118
  end
@@ -112,7 +122,7 @@ class SqdParser < OptionParser
112
122
  end
113
123
 
114
124
  def error_exit(*val, hint)
115
- raise OptionParser::InvalidArgument, message(*val, hint: hint)
125
+ raise OptionParser::InvalidArgument, message(*val, hint: hint), caller(1)
116
126
  end
117
127
  end
118
128
 
@@ -134,7 +144,6 @@ SqdParser.new do |sqd|
134
144
  end
135
145
  sqd.on('-e', '--project-env KEY=STR', 'Provide command ENV variables for :targets (multiple)') do |val|
136
146
  sqd.error_exit('missing value', "#{val}=") unless val.include?('=')
137
-
138
147
  sqd.options[:'project-env'] << val
139
148
  end
140
149
  sqd.separator ''
@@ -145,6 +154,7 @@ SqdParser.new do |sqd|
145
154
  sqd.on('--update', 'Use update strategy for applicable commands') do
146
155
  ENV['UPDATE'] = 'true'
147
156
  end
157
+ sqd.on('--parallel STR,PAT', Array, 'Run standard tasks with multi-task threads')
148
158
  sqd.on('-F', '--force [STR,STR]', Array, 'Enable force through ENV by application') do |val|
149
159
  sqd.parse_common(val, session: session, arg: :FORCE)
150
160
  end
@@ -155,10 +165,9 @@ SqdParser.new do |sqd|
155
165
  ENV['DRY_RUN'] = 'true'
156
166
  end
157
167
  sqd.separator ''
158
- sqd.on('-S', '--select PAGE:CHOICE', 'Prompt menu selection pagination limits') do |val|
168
+ sqd.on('-S', '--select PAGE[:CHOICE]', 'Prompt menu selection pagination display (e.g. 15:75)') do |val|
159
169
  page, choice = val.split(/\D/, 2).map(&:to_i)
160
170
  sqd.error_exit('not an integer', val) if choice.nil? ? page == 0 : choice == 0
161
-
162
171
  session[:PAGE] = page if page > 0
163
172
  session[:CHOICE] = choice if choice.to_i > 0
164
173
  ENV['SELECT'] = "#{page}:#{choice}"
@@ -166,17 +175,14 @@ SqdParser.new do |sqd|
166
175
  sqd.separator ''
167
176
  sqd.on('-p', '--pipe 0|1|2', Integer, 'Set file descriptor for communication') do |val|
168
177
  sqd.error_exit('out of range', val) unless val.between?(0, 2)
169
-
170
178
  session[:PIPE] = val
171
179
  end
172
180
  sqd.on('-o', '--pipe-out FILE', 'Write command data stream to a file') do |val|
173
181
  sqd.error_exit("missing an explicit \".#{File::SEPARATOR}\"", val) unless val.include?(File::SEPARATOR)
174
-
175
182
  session[:OUT] = val
176
183
  end
177
184
  sqd.on('--fail 0..4', Integer, 'Set application exception level') do |val|
178
185
  sqd.error_exit('out of range', val) unless val.between?(0, 4)
179
-
180
186
  session[:FAIL] = val
181
187
  end
182
188
  %i[debug info warn error fatal].then do |state|
@@ -216,9 +222,14 @@ SqdParser.new do |sqd|
216
222
  end
217
223
  sqd.on('--version', 'Print the current version') do
218
224
  puts Squared::VERSION
219
- exit 0
225
+ exit
220
226
  end
221
227
  sqd.on('-h', '--help', 'Print the command line options') do
222
- sqd.help_exit
228
+ if defined?(sqd.help_exit)
229
+ sqd.help_exit
230
+ else
231
+ puts sqd.help
232
+ exit
233
+ end
223
234
  end
224
235
  end.run
@@ -42,7 +42,7 @@ module Squared
42
42
  end
43
43
  rescue Interrupt
44
44
  puts
45
- exit 0
45
+ exit
46
46
  else
47
47
  exit 1 if force
48
48
  false
@@ -122,7 +122,9 @@ module Squared
122
122
  while (ch = Prompt.reline.readline(msg))
123
123
  ch.strip!
124
124
  if !ch.empty?
125
- if multiple
125
+ if ch == '-' && !force
126
+ break
127
+ elsif multiple
126
128
  k = if ch == '*'
127
129
  (min..max).to_a
128
130
  else
@@ -161,7 +163,7 @@ module Squared
161
163
  end
162
164
  rescue Interrupt
163
165
  std.puts
164
- exit 0
166
+ exit
165
167
  else
166
168
  [] if multiple
167
169
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.9.0.pre1'
4
+ VERSION = '0.9.0'
5
5
  end
@@ -163,9 +163,10 @@ module Squared
163
163
  end
164
164
  @pass.items.concat(kwargs[:pass].map { |val| val.is_a?(Regexp) ? val : val.to_s }) if kwargs[:pass]
165
165
  @series = Application.register(self, @base.to_a, exclude: kwargs.fetch(:exclude, []))
166
- if (n = ARG[:APP][:series_ref_min])
167
- @series.ref_min = n
168
- end
166
+ app = ARG[:APP]
167
+ @series.ref_min = app[:series_ref_min] if app.key?(:series_ref_min)
168
+ kwargs[:pattern].concat(app[:build_pattern]) if app.key?(:build_pattern)
169
+ kwargs[:parallel].concat(app[:build_parallel]) if app.key?(:build_parallel)
169
170
  self.closed = 'begin'
170
171
  pb = @stage.key?('project:begin')
171
172
  pe = @stage.key?('project:end')
@@ -406,7 +407,7 @@ module Squared
406
407
  end
407
408
  unless ref.is_a?(Symbol) && (proj = @base.find { |item| item.ref == ref })
408
409
  proj = if !ref.is_a?(Class)
409
- require_project(ref) || Application.find(ref: ref, path: path)
410
+ find_project(ref: ref, path: path)
410
411
  elsif Application.extends(ref)
411
412
  ref
412
413
  end || @kind[name]&.last
@@ -454,6 +455,16 @@ module Squared
454
455
  self
455
456
  end
456
457
 
458
+ def assign(ref = @ref, &blk)
459
+ proj = ref && find_project(ref: ref)
460
+ if proj
461
+ proj.class_eval(&blk)
462
+ else
463
+ warn log_message(Logger::ERROR, 'class not found', subject: main, hint: ref)
464
+ end
465
+ self
466
+ end
467
+
457
468
  def stage(val, first: false, &blk)
458
469
  data = @stage[val]
459
470
  if first == true
@@ -481,7 +492,7 @@ module Squared
481
492
  obj = begin
482
493
  JSON.parse(homepath(obj).read, { symbolize_names: true })
483
494
  rescue => e
484
- warn log_message(Logger::ERROR, e)
495
+ warn log_message(Logger::ERROR, e, subject: main)
485
496
  end
486
497
  end
487
498
  apply_style(data || theme, obj, args, empty: empty) if obj && (!target || data)
@@ -642,16 +653,24 @@ module Squared
642
653
  val = val.split(':') if val.is_a?(String)
643
654
  if before || after || opts
644
655
  pos = []
645
- pos << (before.is_a?(Array) ? before.join(',') : before) if before
646
- if opts
647
- pos << if opts.is_a?(Array)
648
- arg ? "#{arg}=#{opts.join(',')}" : opts.join('|')
656
+ append = lambda do |data|
657
+ pos << case data
658
+ when Array
659
+ data.join(',')
660
+ when Hash
661
+ data.keys.join('|')
649
662
  else
650
- opts
663
+ data
651
664
  end
652
665
  end
653
- pos << (after.is_a?(Array) ? after.join(',') : after) if after
654
- val << "#{val.pop}[#{pos.join(',')}]"
666
+ append.call(before)
667
+ pos << if opts.is_a?(Array)
668
+ arg ? "#{arg}=#{opts.join(',')}" : opts.join('|')
669
+ else
670
+ opts
671
+ end
672
+ append.call(after)
673
+ val << "#{val.pop}[#{pos.compact.join(',')}]"
655
674
  end
656
675
  out ? message(*val) : task_desc(*val)
657
676
  end
@@ -707,12 +726,12 @@ module Squared
707
726
  !@extensions.empty? || any? { |proj| proj.enabled?(base: false) }
708
727
  end
709
728
 
710
- def task_base?(key)
711
- series.base?(key)
729
+ def task_base?(...)
730
+ series.base?(...)
712
731
  end
713
732
 
714
- def task_extend?(obj, key)
715
- series.extend?(obj, key)
733
+ def task_extend?(...)
734
+ series.extend?(...)
716
735
  end
717
736
 
718
737
  def task_include?(obj, key, ref: nil)
@@ -748,12 +767,12 @@ module Squared
748
767
  !!find(home)&.enabled?
749
768
  end
750
769
 
751
- def rootpath(*args)
752
- root.join(*args)
770
+ def rootpath(...)
771
+ root.join(...)
753
772
  end
754
773
 
755
- def homepath(*args)
756
- home.join(*args)
774
+ def homepath(...)
775
+ home.join(...)
757
776
  end
758
777
 
759
778
  def pwd
@@ -1091,6 +1110,10 @@ module Squared
1091
1110
  nil
1092
1111
  end
1093
1112
 
1113
+ def find_project(ref:, path: nil)
1114
+ require_project(ref) || Application.find(ref: ref, path: path)
1115
+ end
1116
+
1094
1117
  def root?(path, pass: [])
1095
1118
  return false unless path.directory?
1096
1119
 
@@ -1139,8 +1139,8 @@ module Squared
1139
1139
  @ref.reverse_each(&blk)
1140
1140
  end
1141
1141
 
1142
- def basepath(*args)
1143
- path.join(*args)
1142
+ def basepath(...)
1143
+ path.join(...)
1144
1144
  end
1145
1145
 
1146
1146
  def basepath!(*args, type: nil)
@@ -1174,10 +1174,20 @@ module Squared
1174
1174
  ret = basepath(*args)
1175
1175
  return ret unless ascend && !ret.exist?
1176
1176
 
1177
+ case ascend
1178
+ when String, Pathname
1179
+ root = Pathname.new(ascend).cleanpath
1180
+ root = nil unless root.absolute? && root.directory?
1181
+ end
1177
1182
  path.parent.ascend.each do |dir|
1178
1183
  target = dir.join(*args)
1179
1184
  return target if target.exist?
1180
- break if (ascend.is_a?(String) && dir.join(ascend).exist?) || workspace.root == dir || parent&.path == dir
1185
+
1186
+ if root
1187
+ break if dir == root
1188
+ elsif workspace.root == dir || parent&.path == dir || (ascend.is_a?(String) && dir.join(ascend).exist?)
1189
+ break
1190
+ end
1181
1191
  end
1182
1192
  ret
1183
1193
  end
@@ -1364,7 +1374,7 @@ module Squared
1364
1374
  run(val, var, sync: sync, banner: banner, **kwargs)
1365
1375
  end
1366
1376
  rescue => e
1367
- on_error(e, exception: kwargs.fetch(:exception, exception?))
1377
+ on_error(e, exception: exception?(**kwargs))
1368
1378
  end
1369
1379
  on :last, from
1370
1380
  end
@@ -2134,6 +2144,10 @@ module Squared
2134
2144
 
2135
2145
  def param_guard(action, flag, args:, key: nil, pat: nil, values: nil)
2136
2146
  if args && key
2147
+ if key.is_a?(Array)
2148
+ return key.map { |val| param_guard(action, flag, args: args, key: val, pat: pat, values: values) }
2149
+ end
2150
+
2137
2151
  val = args.fetch(key, nil)
2138
2152
  return val unless val.nil? || (pat && !val.match?(pat)) || (values && !values.include?(val))
2139
2153
 
@@ -2820,7 +2834,9 @@ module Squared
2820
2834
  workspace.warning
2821
2835
  end
2822
2836
 
2823
- def exception?(*level)
2837
+ def exception?(*level, **kwargs)
2838
+ return kwargs[:exception] if kwargs.key?(:exception)
2839
+
2824
2840
  ret = exception
2825
2841
  return ret unless ret.is_a?(Numeric)
2826
2842
 
@@ -182,7 +182,7 @@ module Squared
182
182
  if flags.nil?
183
183
  case action
184
184
  when 'ls'
185
- format_desc(action, nil, VAL_DOCKER[:ls].keys, after: 'a/ll?,s/tandard?,range*', arg: nil)
185
+ format_desc(action, nil, 'a/ll?,s/tandard?,range*', before: VAL_DOCKER[:ls])
186
186
  task action, [:command] do |_, args|
187
187
  command = param_guard(action, 'command', args: args, key: :command)
188
188
  args = args.extras
@@ -481,8 +481,7 @@ module Squared
481
481
  when :url
482
482
  format_desc action, flag, 'path,url,opts*'
483
483
  task flag, [:path, :url] do |_, args|
484
- path = param_guard(action, flag, args: args, key: :path)
485
- url = param_guard(action, flag, args: args, key: :url)
484
+ path, url = param_guard(action, flag, args: args, key: %i[path url])
486
485
  submodule(flag, args.extras, path: path, url: url)
487
486
  end
488
487
  else
@@ -663,9 +662,9 @@ module Squared
663
662
  when :files
664
663
  format_desc action, flag, 'path1,path2,patch?'
665
664
  task flag, [:path1, :path2, :patch] do |_, args|
666
- path1 = param_guard(action, flag, args: args, key: :path1)
667
- path2 = param_guard(action, flag, args: args, key: :path2)
668
- diff(flag, refs: [path1, path2, args.patch])
665
+ refs = param_guard(action, flag, args: args, key: %i[path1 path2])
666
+ refs << args.patch if args.patch
667
+ diff(flag, refs: refs)
669
668
  end
670
669
  when :grep
671
670
  format_desc action, flag, 'pattern+,a/ll-match?,in/vert-grep?,i/E/F/P?,max-count?=i,f/ormat?=s'
@@ -860,8 +859,7 @@ module Squared
860
859
  when :branch
861
860
  format_desc action, flag, 'branch/:,opts*'
862
861
  task flag, [:branch] do |_, args|
863
- branch = args.branch
864
- branch = nil if branch == ':'
862
+ branch = args.branch unless args.branch == ':'
865
863
  switch(flag, args.extras, branch: branch || choice_refs('Choose a branch'))
866
864
  end
867
865
  end
@@ -889,7 +887,7 @@ module Squared
889
887
  reset(flag, args.to_a, refs: [])
890
888
  end
891
889
  when :mode
892
- format_desc action, flag, 'mode,ref/:'
890
+ format_desc action, flag, 'mode,ref?|:'
893
891
  task flag, [:mode, :ref] do |_, args|
894
892
  mode = param_guard(action, flag, args: args, key: :mode)
895
893
  ref = commithead args.ref
@@ -942,10 +940,13 @@ module Squared
942
940
  when :commit, :'no-commit'
943
941
  format_desc action, flag, 'branch|:,ours|theirs?,opts*'
944
942
  task flag, [:branch] do |_, args|
945
- branch = args.branch
946
- current = git_spawn('branch --show-current').chomp
943
+ branch = if args.branch == ':'
944
+ choice_refs('Choose a branch', accept: "#{action.capitalize}?")
945
+ else
946
+ args.branch
947
+ end
948
+ current = git_value 'branch --show-current'
947
949
  if branch
948
- branch = choice_refs('Choose a branch', accept: "#{action.capitalize}?") if branch == ':'
949
950
  opts = args.extras
950
951
  if has_value!(opts, 'ours')
951
952
  opts << 's=ort' << 'X=ours'
@@ -1070,14 +1071,13 @@ module Squared
1070
1071
  if flag == :add
1071
1072
  format_desc action, flag, 'name,url,opts*'
1072
1073
  task flag, [:name, :url] do |_, args|
1073
- name = param_guard(action, flag, args: args, key: :name)
1074
- url = param_guard(action, flag, args: args, key: :url)
1074
+ name, url = param_guard(action, flag, args: args, key: %i[name url])
1075
1075
  raise ArgumentError, message('invalid url', hint: url) unless url.match?(GIT_PROTO)
1076
1076
 
1077
1077
  git(:remote, args.extras, extras: [name, url])
1078
1078
  end
1079
1079
  else
1080
- format_desc action, flag, "#{OPT_GIT[:remote].keys.join('|')},opts*" if TASK_METADATA
1080
+ format_desc(action, flag, 'opts*', before: OPT_GIT[:remote])
1081
1081
  task flag, [:command] do |_, args|
1082
1082
  command = param_guard(action, flag, args: args, key: :command)
1083
1083
  cmd, opts = git_session('remote', opts: args.extras)
@@ -1201,7 +1201,7 @@ module Squared
1201
1201
  (heads.dup << cur).each_with_index do |branch, i|
1202
1202
  next unless (i < heads.size && cur != branch) || i == heads.size
1203
1203
 
1204
- git_spawn 'switch --quiet', force && '--force', shell_quote(branch)
1204
+ git_spawn('switch --quiet', force && '--force', shell_quote(branch))
1205
1205
  pull(nil, opts, sync: false, hint: branch) if heads.include?(branch)
1206
1206
  end
1207
1207
  return
@@ -1277,13 +1277,13 @@ module Squared
1277
1277
  if flag
1278
1278
  return unless dir && ref
1279
1279
 
1280
- url = git_spawn("config --get remote.#{remotetrack}.url")
1280
+ url = git_value "config --get remote.#{remotetrack}.url"
1281
1281
  cmd, opts = git_session('clone', worktree: false, opts: opts)
1282
1282
  op = OptionPartition.new(opts, OPT_GIT[:clone], cmd, project: self, strict: strict?,
1283
1283
  no: OPT_GIT[:no][:clone])
1284
1284
  op.add_option('b', ref)
1285
1285
  .delim
1286
- .add_quote(url.chomp)
1286
+ .add_quote(url)
1287
1287
  .add_path(dir)
1288
1288
  .clear
1289
1289
  source
@@ -1476,7 +1476,7 @@ module Squared
1476
1476
  end
1477
1477
  return
1478
1478
  end
1479
- sha = git_spawn('rev-parse --verify HEAD').chomp
1479
+ sha = git_value 'rev-parse --verify HEAD'
1480
1480
  return if sha.empty?
1481
1481
 
1482
1482
  sync = kwargs.fetch(:sync) { invoked_sync?('revbuild', flag) }
@@ -1539,7 +1539,7 @@ module Squared
1539
1539
  .clear(pass: false)
1540
1540
  when :commit
1541
1541
  exit 1 unless ref
1542
- branch ||= git_spawn('name-rev --name-only', ref).chomp
1542
+ branch ||= git_value('name-rev --name-only', ref)
1543
1543
  raise ArgumentError, message('could not resolve upstream branch', hint: ref) if branch.empty?
1544
1544
 
1545
1545
  op.append(remotetrack, "#{ref}:#{branch}")
@@ -1734,7 +1734,7 @@ module Squared
1734
1734
  end
1735
1735
  if (n = op.index('>'))
1736
1736
  patch = op.slice!(n, 2)[1]
1737
- elsif !op.exist?(op.last)
1737
+ elsif !op.last.include?('*') && !op.exist?(op.last)
1738
1738
  patch ||= op.pop
1739
1739
  end
1740
1740
  append_pathspec op.extras
@@ -1840,7 +1840,7 @@ module Squared
1840
1840
  if adding.empty? && !cached.empty? && banner?
1841
1841
  puts(cached.lines(chomp: true).map { |val| "cached #{shell_quote(val)}" })
1842
1842
  end
1843
- ENV['COMMIT_PUSH'] = git_spawn 'rev-parse --verify HEAD' if source(co) && source(pu) && !dryrun?
1843
+ ENV['COMMIT_PUSH'] = git_value 'rev-parse --verify HEAD' if source(co) && source(pu) && !dryrun?
1844
1844
  else
1845
1845
  if banner?
1846
1846
  puts 'Nothing to commit'
@@ -1946,7 +1946,8 @@ module Squared
1946
1946
  list_result(ret, 'branches', banner: banner, from: from)
1947
1947
  return
1948
1948
  else
1949
- if (head = git_spawn('rev-parse --abbrev-ref HEAD').chomp).empty?
1949
+ head = git_value 'rev-parse --abbrev-ref HEAD'
1950
+ if head.empty?
1950
1951
  ret = 0
1951
1952
  else
1952
1953
  git_spawn 'fetch --all --prune --quiet' if option('sync')
@@ -2044,7 +2045,7 @@ module Squared
2044
2045
  else
2045
2046
  ref
2046
2047
  end)
2047
- return git_spawn(cmd, exception: false).chomp
2048
+ return git_value(cmd, exception: false)
2048
2049
  when :output
2049
2050
  if opts.delete('sq-quote')
2050
2051
  cmd << '--sq-quote'
@@ -2326,7 +2327,7 @@ module Squared
2326
2327
  ret = choice_index(msg, git_spawn(cmd, stdout: false), column: /^(\S+)/, force: force, **kwargs)
2327
2328
  case ret
2328
2329
  when Array
2329
- ret.map { |val| val&.stripstyle }
2330
+ ret.map { |val| val.is_a?(Array) ? val.map { |s| s&.stripstyle } : val&.stripstyle }
2330
2331
  when String
2331
2332
  ret.stripstyle
2332
2333
  else
@@ -2504,6 +2505,10 @@ module Squared
2504
2505
  stdout: stdout, banner: banner, **kwargs)
2505
2506
  end
2506
2507
 
2508
+ def git_value(*cmd, exception: true)
2509
+ git_spawn(*cmd, exception: exception).chomp
2510
+ end
2511
+
2507
2512
  def git_grep(cmd, *grep, equals: true, **kwargs)
2508
2513
  ret = []
2509
2514
  git_spawn(cmd, **kwargs).lines(chomp: true).each do |line|