squared 0.6.7 → 0.6.9

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: 73203f27b80dac94c1a96127b27afeb60d939e27adc578724264c9db26380ac0
4
- data.tar.gz: 308784d8e94aefcb5b2da4b75e6614bb94e6d1a5d66fc4754d7e72072655e588
3
+ metadata.gz: bd07ce40c31b81be676defc0120ee1090e6bf020153b0234bcc9656e791279d3
4
+ data.tar.gz: e4179c5daf66d93a6795a3a15be28f93936d90da081fdfde2f779d05cddbc20e
5
5
  SHA512:
6
- metadata.gz: 1f477ca8a24e892a052a2375283fbbf08af5cfc4714eaadba8c9465d59ad20e5d9bc6ae6cd624ff09780d62831cf2355918f01a851bbe09c52861d45479b1b6b
7
- data.tar.gz: 289b353519bd3d5d7b13eb6f190428c74d9f4975e176094e65ba052a1febf28b2d719210efae09768cf0c3729d03b944bfd2344bde2025705cf2b0627d6bdfeb
6
+ metadata.gz: 437e260ef864d9734038ef84cf17bef22582d68f0081f4a8a7c4c16157bc32b3322673d2cb069ee84313b61243df30d65e3a3be432d613a2b977981e95b32aae
7
+ data.tar.gz: 02efccc2029b33cdfa91cf0da6454f7c9116e12320c7a378d8ccdf19d16a70414f36999fbf97bfd975ca24007c932e3d62d13753c4227ca565e6c569e3a36824
data/CHANGELOG.md CHANGED
@@ -1,5 +1,76 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.9] - 2025-01-07
4
+
5
+ ### Added
6
+
7
+ - Bundler command config can be executed without [set|get] actions.
8
+
9
+ ### Changed
10
+
11
+ - Application method with using hide and pass compatibility was implemented.
12
+
13
+ ## [0.5.21] - 2025-12-31
14
+
15
+ ### Fixed
16
+
17
+ - See `0.4.35`.
18
+
19
+ ## [0.4.35] - 2025-12-31
20
+
21
+ ### Changed
22
+
23
+ - Ruby task copy uses GEM_HOME as fallback for autodetect.
24
+
25
+ ### Fixed
26
+
27
+ - Git commands [rebase|clone] did not forward sync flag.
28
+ - Pip command install carelessly used an undefined method.
29
+ - Common prompt method readline with multiline did not permit empty lines.
30
+ - Application method with using pass did not ignore exceptions.
31
+ - Git method source did not check command object for supported method.
32
+
33
+ ## [0.6.8] - 2025-12-26
34
+
35
+ ### Added
36
+
37
+ - Ruby attribute project is extracted from Gemspec.
38
+
39
+ ### Changed
40
+
41
+ - Project base task unpack no longer hard codes any extensions.
42
+
43
+ ### Fixed
44
+
45
+ - Gem command outdated did not set bindir with update command.
46
+ - Bundler ultimately never ended up learning how to spell JIT.
47
+
48
+ ## [0.5.20] - 2025-12-26
49
+
50
+ ### Fixed
51
+
52
+ - Bundle config get method did not always discard newline.
53
+
54
+ ## [0.4.34] - 2025-12-26
55
+
56
+ ### Added
57
+
58
+ - Project public base method scope for nested tasks was created.
59
+ - Ruby task copy can autodetect "env" using [GEM_HOME|GEM_ROOT].
60
+
61
+ ### Changed
62
+
63
+ - Python virtual environment did not install poetry during initialization.
64
+
65
+ ### Fixed
66
+
67
+ - Workspace global banner never referenced the correct hash key.
68
+ - Python task depend without editable did not append context directory.
69
+ - Docker task build did not parse DOCKER_OPTIONS as command options.
70
+ - Project base method build did not call Method routines.
71
+ - Bundler autodetect did not check for valid gems directory.
72
+ - Ruby copy to version detection did not check for valid gemspec.
73
+
3
74
  ## [0.6.7] - 2025-12-07
4
75
 
5
76
  ### Added
@@ -1524,6 +1595,8 @@
1524
1595
 
1525
1596
  - Changelog was created.
1526
1597
 
1598
+ [0.6.9]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.9
1599
+ [0.6.8]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.8
1527
1600
  [0.6.7]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.7
1528
1601
  [0.6.6]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.6
1529
1602
  [0.6.5]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.5
@@ -1532,6 +1605,8 @@
1532
1605
  [0.6.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.2
1533
1606
  [0.6.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.1
1534
1607
  [0.6.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.0
1608
+ [0.5.21]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.21
1609
+ [0.5.20]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.20
1535
1610
  [0.5.19]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.19
1536
1611
  [0.5.18]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.18
1537
1612
  [0.5.17]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.17
@@ -1552,6 +1627,8 @@
1552
1627
  [0.5.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.2-ruby
1553
1628
  [0.5.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.1-ruby
1554
1629
  [0.5.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.0-ruby
1630
+ [0.4.35]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.35
1631
+ [0.4.34]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.34
1555
1632
  [0.4.33]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.33
1556
1633
  [0.4.32]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.32
1557
1634
  [0.4.31]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.31
data/README.md CHANGED
@@ -75,7 +75,7 @@ Workspace::Application
75
75
  .add("e-mc", "emc", copy: { from: "publish", scope: "@e-mc", also: [:pir, "squared-express/"] }, ref: :node) # Node
76
76
  .add("pi-r", "pir", copy: { from: "publish", scope: "@pi-r" }, clean: ["publish/**/*.js", "tmp/"]) # Trailing slash required for directories
77
77
  .add("pi-r2", "pir2", copy: { from: :npm, also: %i[squared express], files: ["LICENSE", ["README.md.ruby", "README.md"]] }) # Uses dist files from NPM package spec
78
- .add("squared", init: 'pnpm', script: ["build:stage1", "build:stage2"], group: "app") do # Use pnpm/yarn/berry for depend + Copy target (main)
78
+ .add("squared", init: "pnpm", script: ["build:stage1", "build:stage2"], group: "app") do # Use pnpm/yarn/berry for depend + Copy target (main)
79
79
  # Repo (global)
80
80
  as(:run, "build:dev", "dev") # npm run build:dev -> npm run dev
81
81
  as(:run, { "build:dev": "dev", "build:prod": "prod" })
@@ -165,7 +165,7 @@ Workspace::Application
165
165
  .each(&:join)
166
166
  }
167
167
  apply :lint, proc {
168
- bundle("exec", "-A --cache=true", with: "lint", verbose: true) # bundle exec --gemfile='/squared/Gemfile' rubocop --parallel -A --cache=true
168
+ bundle("exec", "-A --cache=true", with: "lint", verbose: true) # bundle exec --gemfile="/squared/Gemfile" rubocop --parallel -A --cache=true
169
169
  }
170
170
  end
171
171
  .with(:python, editable: false) do # ref=Symbol | group=String
@@ -567,7 +567,7 @@ Commands which use commit hashes are parsed using a ":" prefix as to not be conf
567
567
 
568
568
  ```sh
569
569
  rake squared:log:view[:af012345] # git log af012345
570
- rake squared:log:view[H1,HEAD^5,all,lib,./H12345] # git log --all @~1 @^5 -- 'lib' 'H12345'
570
+ rake squared:log:view[H1,HEAD^5,all,lib,./H12345] # git log --all @~1 @^5 -- "lib" "H12345"
571
571
  ```
572
572
 
573
573
  ## Environment
@@ -723,7 +723,7 @@ DOCKER_ALL=1 # list every image/container
723
723
  DOCKER_Y=1 # confirm all
724
724
 
725
725
  BUILD_SQUARED_OPTS="NODE_TAG=24 RUBY_VERSION=3.4.0" DOCKER_SQUARED_OPTS="--no-cache --label=v1" rake squared:build
726
- docker build --no-cache --label=v1 --build-arg='NODE_TAG=24' --build-arg='RUBY_VERSION=3.4.0' .
726
+ docker build --no-cache --label=v1 --build-arg="NODE_TAG=24" --build-arg="RUBY_VERSION=3.4.0" .
727
727
  ```
728
728
 
729
729
  | Command | Flag | ENV |
@@ -839,7 +839,8 @@ Features can be enabled through ENV when calling global tasks such as through *C
839
839
  | depend package | * | PACAKGE_LOCK|LOCKFILE=0 NO_LOCKFILE=1 Y |
840
840
  | npm pnpm | depend package | CPU=s OS=s LIBC=s |
841
841
  | npm | package | SAVE IGNORE_SCRIPTS STRICT_PEER_DEPS |
842
- | pnpm | depend | ALLOW_BUILD=s PUBLIC_HOIST_PATTERN=s |
842
+ | pnpm | depend | PUBLIC_HOIST_PATTERN=s APPROVE_BUILDS |
843
+ | pnpm | depend:add | ALLOW_BUILD=s |
843
844
  | yarn | depend package | IGNORE_ENGINES=0 |
844
845
 
845
846
  #### Python
@@ -261,6 +261,8 @@ module Squared
261
261
  lines = val.to_s.lines(chomp: true)
262
262
  lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(::StandardError))
263
263
  end
264
+ return if lines.empty?
265
+
264
266
  n = (cols.is_a?(::Array) ? cols.map(&:size).max : cols) || max.call(lines)
265
267
  if $stdout.tty?
266
268
  require 'io/console'
@@ -89,7 +89,8 @@ module Squared
89
89
  k = if ch == '*'
90
90
  (min..max).to_a
91
91
  else
92
- ch.split(/\s*,\s*/).map! do |s|
92
+ ch.split(',').map! do |s|
93
+ s.strip!
93
94
  if s =~ /^(\d+)-(\d+)$/
94
95
  next unless between.call($1) && between.call($2)
95
96
 
@@ -137,7 +138,11 @@ module Squared
137
138
  elsif block_given?
138
139
  Readline.readmultiline(msg, history, &blk)
139
140
  else
140
- Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val.to_s) } }
141
+ Readline.readmultiline(msg, history) do |line|
142
+ next if line.strip.empty?
143
+
144
+ multiline.any? { |val| line.split.last.end_with?(val.to_s) }
145
+ end
141
146
  end
142
147
  end
143
148
  case force
@@ -150,6 +150,7 @@ module Squared
150
150
  end
151
151
 
152
152
  def shell_bin(name, env: true)
153
+ require_relative 'base'
153
154
  key = name.to_s.upcase
154
155
  key = File.basename(key, '.*') if Rake::Win32.windows?
155
156
  shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.6.7'
4
+ VERSION = '0.6.9'
5
5
  end
@@ -201,8 +201,25 @@ module Squared
201
201
  self
202
202
  end
203
203
 
204
- def with(*val, pass: false, group: nil, **kwargs, &blk)
205
- return self if pass == true || (pass && as_a(pass, :to_s).any? { |s| respond_to?(s) && __send__(s) })
204
+ def with(*val, hide: nil, group: nil, **kwargs, &blk)
205
+ if hide.nil? && kwargs.key?(:pass)
206
+ pass = kwargs[:pass]
207
+ case pass
208
+ when true, false
209
+ hide = pass
210
+ kwargs.delete(:pass)
211
+ else
212
+ hide, pass = Array(pass).partition { |s| respond_to?(s) || s.to_s.end_with?('?') }
213
+ if pass.empty?
214
+ kwargs.delete(:pass)
215
+ elsif hide.empty?
216
+ hide = nil
217
+ else
218
+ kwargs[:pass] = pass
219
+ end
220
+ end
221
+ end
222
+ return self if hide == true || (hide && Array(hide).any? { |s| respond_to?(s) && __send__(s) rescue nil })
206
223
 
207
224
  @group = nil
208
225
  @ref = nil
@@ -298,9 +315,9 @@ module Squared
298
315
 
299
316
  def pass(name, group: @group, ref: @ref, &blk)
300
317
  data = if group
301
- @pass[:group][group]
318
+ @pass[:group][group.to_s]
302
319
  elsif ref
303
- @pass[:ref][ref]
320
+ @pass[:ref][ref.to_sym]
304
321
  else
305
322
  @pass[:global]
306
323
  end
@@ -606,7 +623,7 @@ module Squared
606
623
  return ret if group && (ret = @banner[:group][group.to_sym])
607
624
 
608
625
  ref.reverse_each { |val| return ret if (ret = @banner[:ref][val]) }
609
- @banner[:ref][:'']
626
+ @banner[:ref][:_]
610
627
  end
611
628
 
612
629
  def enabled?
@@ -396,13 +396,12 @@ module Squared
396
396
  tag = param_guard(action, flag, args: args, key: :tag)
397
397
  dir = param_guard(action, flag, args: args, key: :dir)
398
398
  unless tag.match?(URI_SCHEME)
399
- tag = if ext == 'gem'
400
- "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
401
- elsif @release
402
- "%s.#{ext}" % [@release.include?('??') ? @release.sub('??', tag) : @release + tag]
403
- else
404
- raise_error ArgumentError, "no base uri: #{tag}", hint: ext
405
- end
399
+ tag = unpack_get tag, ext
400
+ tag ||= if @release
401
+ "%s.#{ext}" % [@release.include?('??') ? @release.sub('??', tag) : @release + tag]
402
+ else
403
+ raise_error ArgumentError, "no base uri: #{tag}", hint: ext
404
+ end
406
405
  end
407
406
  force = case (digest = args.digest)
408
407
  when 'f', 'force'
@@ -509,7 +508,7 @@ module Squared
509
508
  end
510
509
 
511
510
  def build(*args, sync: invoked_sync?('build'), from: :run, **)
512
- banner = verbose
511
+ banner = !silent?
513
512
  if args.empty?
514
513
  return unless from == :run
515
514
 
@@ -526,8 +525,14 @@ module Squared
526
525
  cmd = []
527
526
  var = {}
528
527
  args.each do |val|
529
- next instance_exec(*val[1..-1], &val.first) if val.first.is_a?(Proc)
530
-
528
+ case val.first
529
+ when Proc
530
+ instance_exec(*val[1..-1], &val.first)
531
+ next
532
+ when Method
533
+ val.first.call(*val[1..-1])
534
+ next
535
+ end
531
536
  a, b, c, d, e = val
532
537
  case b
533
538
  when Hash
@@ -711,7 +716,7 @@ module Squared
711
716
  end
712
717
 
713
718
  def unpack(target, file = nil, uri: nil, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {},
714
- verbose: self.verbose, from: :unpack)
719
+ verbose: !silent?, from: :unpack)
715
720
  if !target.exist?
716
721
  target.mkpath
717
722
  elsif !target.directory?
@@ -862,6 +867,7 @@ module Squared
862
867
  end
863
868
  cmd << name << version
864
869
  when :exec
870
+ cmd << name unless opts.first.start_with?(/#{name}\b/)
865
871
  cmd.merge(opts)
866
872
  when :current
867
873
  cmd << '--no-header' unless legacy
@@ -961,6 +967,12 @@ module Squared
961
967
  end
962
968
  end
963
969
 
970
+ def scope(*args, **kwargs, &blk)
971
+ namespace name do
972
+ task(*args, **kwargs, &blk)
973
+ end
974
+ end
975
+
964
976
  def variable_set(key, *args, **kwargs, &blk)
965
977
  if block_given?
966
978
  if blocks.include?(key)
@@ -995,7 +1007,8 @@ module Squared
995
1007
  when :env
996
1008
  run_set(output[0], *args, **kwargs)
997
1009
  when :dependfile
998
- @dependfile = basepath(*args)
1010
+ @dependindex = nil
1011
+ @dependfile = val.nil? ? nil : basepath(*args)
999
1012
  else
1000
1013
  instance_variable_set(:"@#{key}", val)
1001
1014
  end
@@ -1213,8 +1226,7 @@ module Squared
1213
1226
  run(val, var, sync: sync, banner: banner, **kwargs)
1214
1227
  end
1215
1228
  rescue StandardError => e
1216
- ret = on :error, from, e
1217
- raise unless ret == true
1229
+ on_error(e, from, exception: kwargs.fetch(:exception, exception))
1218
1230
  end
1219
1231
  on :last, from
1220
1232
  end
@@ -1264,6 +1276,8 @@ module Squared
1264
1276
  else
1265
1277
  items = data[target.name] - done
1266
1278
  end
1279
+ return done if items.empty?
1280
+
1267
1281
  if out
1268
1282
  a, b, c, d, e = ARG[:GRAPH]
1269
1283
  f = tag.call(target)
@@ -1357,8 +1371,8 @@ module Squared
1357
1371
  if (obj = workspace.find(name: val))
1358
1372
  obj.enabled? ? [obj] : []
1359
1373
  else
1360
- workspace.find(group: val, ref: val.to_sym)
1361
- end.sort.each do |proj|
1374
+ workspace.find(group: val, ref: val.to_sym).sort
1375
+ end.each do |proj|
1362
1376
  next if pass.include?(name = proj.name)
1363
1377
 
1364
1378
  if proj.graph? && !data.key?(name) && !root.include?(name)
@@ -1528,7 +1542,7 @@ module Squared
1528
1542
  end
1529
1543
 
1530
1544
  def print_run(cmd, banner = true, verbose: nil, **)
1531
- return if banner || !stdout? || verbose == false
1545
+ return if banner || !stdout? || verbose == false || env('BANNER', equals: '0')
1532
1546
 
1533
1547
  puts "\n> #{cmd}"
1534
1548
  printsucc
@@ -1712,7 +1726,9 @@ module Squared
1712
1726
  next if val.nil?
1713
1727
  end
1714
1728
  case val
1715
- when Array
1729
+ when Hash
1730
+ append_hash(val, target: target, build: build)
1731
+ when Enumerable
1716
1732
  append_repeat(key, val, target: target)
1717
1733
  when Numeric
1718
1734
  target << basic_option(key, val)
@@ -1796,10 +1812,10 @@ module Squared
1796
1812
  next unless data.key?(key)
1797
1813
 
1798
1814
  out[key] = case (val = data[key])
1799
- when Array
1800
- base.fetch(key, []) + val
1801
1815
  when Hash
1802
1816
  base.fetch(key, {}).update(val)
1817
+ when Enumerable
1818
+ Array(base.fetch(key, [])) + val.to_a
1803
1819
  else
1804
1820
  val
1805
1821
  end
@@ -2008,7 +2024,9 @@ module Squared
2008
2024
 
2009
2025
  def command(*args, verbose: true)
2010
2026
  out = unless verbose
2011
- [">#{File::NULL}", '2>&1'].tap { |a| a.reverse if File::NULL == 'NUL' }.unshift('').join(' ')
2027
+ cmd = [">#{File::NULL}", '2>&1']
2028
+ cmd.reverse! if File::NULL == 'NUL'
2029
+ cmd.unshift('').join(' ')
2012
2030
  end
2013
2031
  if workspace.powershell?
2014
2032
  "#{shell_bin('powershell.exe')} -Command \"& {#{args.join(' ; ')}}\"#{out}"
@@ -2254,7 +2272,9 @@ module Squared
2254
2272
  end
2255
2273
  self.global = global
2256
2274
  case cmd
2257
- when Array
2275
+ when Hash
2276
+ @output = parse.call(data)
2277
+ when Enumerable
2258
2278
  @output = if cmd.all? { |data| data.is_a?(Hash) }
2259
2279
  noopt = false
2260
2280
  noenv = false
@@ -2263,8 +2283,6 @@ module Squared
2263
2283
  cmd.dup
2264
2284
  end
2265
2285
  return
2266
- when Hash
2267
- @output = parse.call(data)
2268
2286
  else
2269
2287
  @output[0] = cmd
2270
2288
  end
@@ -2362,6 +2380,10 @@ module Squared
2362
2380
  (global && @as[from][val]) || val
2363
2381
  end
2364
2382
 
2383
+ def unpack_get(*)
2384
+ nil
2385
+ end
2386
+
2365
2387
  def task_build(keys)
2366
2388
  namespace name do
2367
2389
  ws = workspace
@@ -323,21 +323,20 @@ module Squared
323
323
  def compose(opts, flags = nil, script: false, args: nil, from: :run, **)
324
324
  return opts unless script
325
325
 
326
- ret = docker_session
327
326
  if from == :run
328
327
  if bake?(n = filetype)
329
- ret << 'buildx bake'
328
+ ret = docker_session 'buildx bake'
330
329
  append_file n
331
330
  from = :bake
332
331
  elsif compose?(n)
333
- ret << 'compose build'
332
+ ret = docker_session 'compose build'
334
333
  append_file n
335
334
  from = :compose
336
335
  else
337
- ret << 'build'
336
+ ret = docker_session 'build'
338
337
  end
339
338
  else
340
- ret << from
339
+ ret = docker_session from
341
340
  end
342
341
  case opts
343
342
  when String
@@ -775,8 +774,8 @@ module Squared
775
774
  [cmd, status, no]
776
775
  end
777
776
 
778
- def list_image(flag, cmd = docker_output('image ls -a'), hint: nil, from: nil, no: true)
779
- pwd_set do
777
+ def list_image(flag, cmd = docker_output('image ls -a'), hint: nil, no: true, from: nil)
778
+ pwd_set(from: from) do
780
779
  index = 1
781
780
  all = option('all', prefix: 'docker')
782
781
  y = from == :'image:rm' && option('y', prefix: 'docker')
@@ -1075,7 +1075,7 @@ module Squared
1075
1075
 
1076
1076
  cmd << "--#{command}"
1077
1077
  end
1078
- source
1078
+ source(sync: sync)
1079
1079
  end
1080
1080
 
1081
1081
  def autostash(*, sync: invoked_sync?('autostash'), **)
@@ -1128,7 +1128,7 @@ module Squared
1128
1128
  append_hash opts
1129
1129
  cmd << '--quiet' if option('quiet') || !verbose
1130
1130
  append_value(data[0], path, delim: true)
1131
- source(banner: sync && !quiet?, multiple: !sync || quiet?)
1131
+ source(sync: sync, banner: sync && !quiet?, multiple: !sync || quiet?)
1132
1132
  end
1133
1133
 
1134
1134
  def stash(flag = nil, opts = [], sync: invoked_sync?('stash', flag))
@@ -1892,16 +1892,19 @@ module Squared
1892
1892
  banner = nil unless banner? && !multiple
1893
1893
  args = true
1894
1894
  end
1895
- if from.nil? && (from = cmd.drop(1).find { |val| val.match?(/\A[a-z]{1,2}[a-z-]*\z/) })
1896
- from = :"git:#{from}"
1897
- elsif from == false
1895
+ if from == false
1898
1896
  from = nil
1897
+ elsif !from && cmd.respond_to?(:drop)
1898
+ from = cmd.drop(1).find { |val| val.match?(/\A[a-z]{1,2}[a-z-]*\z/) }
1899
+ from &&= :"git:#{from}"
1899
1900
  end
1900
1901
  banner &&= cmd.temp { |val| val.start_with?(/--(?:work-tree|git-dir)/) } if cmd.respond_to?(:temp)
1901
1902
  end
1902
1903
  cmd = session_done cmd
1903
1904
  log&.info cmd
1904
- banner = format_banner(banner.is_a?(String) ? banner : cmd, hint: hint, strip: true) if banner
1905
+ banner = if banner
1906
+ format_banner(banner.is_a?(String) ? banner : cmd, hint: hint, strip: true)
1907
+ end
1905
1908
  on :first, from
1906
1909
  begin
1907
1910
  if io
@@ -1910,11 +1913,11 @@ module Squared
1910
1913
  return args ? [IO.popen(cmd), banner || '', from] : IO.popen(cmd)
1911
1914
  elsif stdin? ? sync : stdout
1912
1915
  print_item banner unless multiple
1913
- ret = `#{cmd}`
1914
- raise(ret.chomp.empty? ? $?.to_s : ret) unless $?.success?
1916
+ ret = `#{cmd}`.chomp
1917
+ raise(ret.empty? ? $?.to_s : ret) unless $?.success?
1915
1918
 
1916
1919
  if ret.empty?
1917
- success?(nil, !banner.nil?)
1920
+ success?(true, !banner.nil?)
1918
1921
  else
1919
1922
  puts ret
1920
1923
  end
@@ -1928,7 +1931,7 @@ module Squared
1928
1931
  n = write_lines(out, banner: banner, pass: true, **kwargs)
1929
1932
  if n == 0
1930
1933
  n = write_lines(err, banner: banner)
1931
- success?(nil, n == 0 && !banner.nil?)
1934
+ success?(n == 0, n == 0 && !banner.nil?)
1932
1935
  else
1933
1936
  write_lines(err, loglevel: Logger::DEBUG)
1934
1937
  end
@@ -31,7 +31,8 @@ module Squared
31
31
  use-running-store-server use-store-server child-concurrency=i hoist-pattern=q lockfile-dir=p
32
32
  modules-dir=p network-concurrency=i package-import-method=b public-hoist-pattern=q
33
33
  reporter=b].freeze,
34
- install_a: %w[global-dir ignore-scripts offline prefer-offline store-dir=p virtual-store-dir=p].freeze,
34
+ install_a: %w[dangerously-allow-all-builds global-dir ignore-scripts offline prefer-offline store-dir=p
35
+ virtual-store-dir=p].freeze,
35
36
  install_b: %w[D|dev no-optional P|prod].freeze,
36
37
  add: %w[allow-build config g|global save-catalog D|save-dev O|save-optional save-peer P|save-prod
37
38
  save-catalog-name=b].freeze,
@@ -577,6 +578,7 @@ module Squared
577
578
  '--frozen-lockfile'
578
579
  end
579
580
  cmd << '--ignore-scripts' if option('ignore-scripts')
581
+ cmd << '--dangerously-allow-all-builds' if option('approve-builds')
580
582
  else
581
583
  cmd = session 'npm'
582
584
  cmd << (ci = option('ci') ? 'ci' : 'install')
@@ -875,7 +877,7 @@ module Squared
875
877
  log.info cmd.to_s
876
878
  end
877
879
  if sync
878
- run(from: from, sync: sync, interactive: !dryrun && ['Publish', 'N', npmname])
880
+ run(sync: sync, from: from, interactive: !dryrun && ['Publish', 'N', npmname])
879
881
  else
880
882
  require 'open3'
881
883
  on :first, from
@@ -1053,7 +1055,7 @@ module Squared
1053
1055
  raise_error 'version not found', hint: dependfile
1054
1056
  end
1055
1057
  rescue StandardError => e
1056
- on_error e, :bump
1058
+ on_error(e, :bump, dryrun: dryrun?)
1057
1059
  end
1058
1060
 
1059
1061
  def pack(opts = [])
@@ -45,15 +45,15 @@ module Squared
45
45
  OPT_POETRY = {
46
46
  common: %w[ansi no-ansi no-cache n|no-interaction no-plugins q|quiet=+ v|verbose=+ P|project=p].freeze,
47
47
  build: %w[clean config-settings=qq f|format=b o|output=p].freeze,
48
- publish: %w[build dry-run skip-existing cert=p client-cert=p dist-dir=p p|password=b r|repository=q
49
- u|username=b].freeze
48
+ publish: %w[build dry-run skip-existing cert=p client-cert=p dist-dir=p p|password=q r|repository=q
49
+ u|username=qq].freeze
50
50
  }.freeze
51
51
  OPT_PDM = {
52
52
  common: %w[I|ignore-python no-cache n|non-interactive].freeze,
53
53
  build: %w[C=bm no-clean no-isolation no-sdist no-wheel q|quiet v|verbose=+ config-setting=q d|dest=p
54
54
  p|project=p k|skip=b].freeze,
55
55
  publish: %w[no-build no-very-ssl q|quiet S|sign skip-existing v|verbose=+ ca-certs=p c|comment=q d|dest=p
56
- i|identity=b P|password=q p|project=p r|repository=q k|skip=b u|username=b].freeze
56
+ i|identity=b P|password=q p|project=p r|repository=q k|skip=b u|username=qq].freeze
57
57
  }.freeze
58
58
  OPT_HATCH = {
59
59
  common: %w[color interactive no-color no-interactive cache-dir=p config=p data-dir=p e|env=b p|project=b
@@ -65,7 +65,7 @@ module Squared
65
65
  OPT_TWINE = {
66
66
  publish: %w[attestations disable-progress-bar non-interactive s|sign skip-existing verbose cert=p
67
67
  client-cert=p c|comment=q config-file=p i|identity=b p|password=q r|repository=b repository-url=q
68
- sign-with=b u|username=q].freeze
68
+ sign-with=b u|username=qq].freeze
69
69
  }.freeze
70
70
  PASS_PYTHON = {
71
71
  python: %w[c v V].freeze,
@@ -386,6 +386,7 @@ module Squared
386
386
  cmd << '--no-root' if option('no-root')
387
387
  else
388
388
  cmd = pip_session 'install'
389
+ cmd << '--upgrade-strategy=eager' if env('PYTHON_UPDATE')
389
390
  if flag
390
391
  case flag
391
392
  when :user
@@ -403,7 +404,7 @@ module Squared
403
404
  cmd << "-r #{DEP_PYTHON[4]}" if exist?(DEP_PYTHON[4]) && !session_arg?('r', 'requirement')
404
405
  append_editable
405
406
  end
406
- run(from: :depend, sync: sync)
407
+ run(sync: sync, from: :depend)
407
408
  end
408
409
  end
409
410
 
@@ -588,7 +589,6 @@ module Squared
588
589
  if !ENV['HATCH_BUILD_LOCATION'] && (outdir ||= op.shift)
589
590
  op.add_path(outdir)
590
591
  end
591
- op << basic_option('p', project) unless ENV['HATCH_PROJECT'] || op.arg?('p', 'project')
592
592
  else
593
593
  unless op.empty?
594
594
  args = case flag
@@ -762,17 +762,21 @@ module Squared
762
762
  end
763
763
  case key
764
764
  when :dependfile
765
- val = basepath(*args)
766
- if (index = DEP_PYTHON.index(val.basename.to_s))
767
- @dependindex = index
768
- @dependfile = val
765
+ if args.first.nil?
766
+ super
769
767
  else
770
- log.warn "variable_set: @#{key}=#{val} (not supported)"
768
+ val = basepath(*args)
769
+ if (index = DEP_PYTHON.index(val.basename.to_s))
770
+ @dependindex = index
771
+ @dependfile = val
772
+ else
773
+ log.warn "variable_set: @#{key}=#{val} (not supported)"
774
+ end
771
775
  end
772
776
  when :editable
773
777
  editable_set args.first
774
778
  when :venv
775
- instance_variable_set(:"@#{key}", (basepath(*args) unless args.empty?))
779
+ @venv = args.empty? || args.first.nil? ? nil : basepath(*args)
776
780
  else
777
781
  super
778
782
  end
@@ -797,10 +801,11 @@ module Squared
797
801
  end
798
802
 
799
803
  def python_session(*cmd, opts: nil)
800
- return session('python', *preopts(quiet: false), *cmd, path: venv.nil?) unless opts
804
+ pre = preopts(quiet: false)
805
+ return session('python', *pre, *cmd, path: venv.nil?) unless opts
801
806
 
802
807
  op = OptionPartition.new(opts, OPT_PYTHON[:common], project: self, single: singleopt(:python))
803
- [session('python', *op.to_a, *cmd, path: venv.nil?), op.extras]
808
+ [session('python', *pre, *op.to_a, *cmd, path: venv.nil?), op.extras]
804
809
  end
805
810
 
806
811
  def poetry_session(*cmd)
@@ -820,8 +825,8 @@ module Squared
820
825
  def create_session(*cmd, name:, common:, opts: nil)
821
826
  return session(name, *preopts, *cmd, path: venv.nil?) unless opts
822
827
 
823
- op = OptionPartition.new(opts, common, project: self, single: singleopt)
824
- [session(name, *op.to_a, *cmd, path: venv.nil?), op.extras]
828
+ op = OptionPartition.new(opts, common, project: self, single: singleopt(name.to_sym))
829
+ [session(name, *preopts, *op.to_a, *cmd, path: venv.nil?), op.extras]
825
830
  end
826
831
 
827
832
  def append_pip(flag, opts, target: @session, from: nil)
@@ -877,14 +882,16 @@ module Squared
877
882
  OptionPartition.delete_key(target, 'e', 'editable')
878
883
  case val
879
884
  when '0', 'false'
880
- return
885
+ return unless installable?
881
886
  else
882
887
  val = basepath val
883
888
  end
884
- elsif session_arg?('e', 'editable', target: target) || !(val = editable)
889
+ elsif session_arg?('e', 'editable', target: target) || !installable?
885
890
  return
891
+ else
892
+ val = editable
886
893
  end
887
- target << quote_option('e', basepath(val))
894
+ target << (val ? quote_option('e', basepath(val)) : '.')
888
895
  end
889
896
 
890
897
  def append_global(target: @session)
@@ -1063,9 +1070,9 @@ module Squared
1063
1070
  status = op.append(dir, delim: true)
1064
1071
  .clear(pass: false)
1065
1072
  .arg?(/\A-v+\z/)
1066
- success?(run(op, env, exception: true, banner: banner), banner, !status) do |ret|
1067
- puts(ret && dir.directory? ? "Success: #{dir}" : 'Failed')
1068
- end
1073
+ ret = run(op, env, exception: true, banner: banner)
1074
+ pip(:install, 'poetry', banner: false) if poetry?
1075
+ success?(ret, banner, !status) { |out| puts(out && dir.directory? ? "Success: #{dir}" : 'Failed') }
1069
1076
  end
1070
1077
 
1071
1078
  def pip_install?(flag)
@@ -48,7 +48,7 @@ module Squared
48
48
  cache: %w[frozen no-all no-install no-prune quiet cache-path=p gemfile=p].freeze,
49
49
  check: %w[dry-run gemfile=p path=p].freeze,
50
50
  clean: %w[dry-run force].freeze,
51
- config: %w[global local].freeze,
51
+ config: %w[global local skip-parseable].freeze,
52
52
  doctor: %w[quiet ssl gemfile=p].freeze,
53
53
  doctor_ssl: %w[host=q tls-version=b verify-mode=b].freeze,
54
54
  exec: %w[gemfile=p].freeze,
@@ -69,6 +69,7 @@ module Squared
69
69
  show: %w[outdated paths].freeze,
70
70
  update: %w[all conservative local major minor patch pre ruby strict bundler=b? g|group=q source=q].freeze,
71
71
  no: {
72
+ config: %w[parseable].freeze,
72
73
  gem: %w[changelog ci coc exe linter mit test].freeze
73
74
  }.freeze
74
75
  }.freeze
@@ -223,6 +224,10 @@ module Squared
223
224
  end
224
225
  end
225
226
 
227
+ def project=(val)
228
+ @project = val.dup
229
+ end
230
+
226
231
  def gemdir=(val)
227
232
  @gemdir = if val.is_a?(Pathname)
228
233
  val
@@ -438,10 +443,10 @@ module Squared
438
443
  when :exec then 'command,args*|:'
439
444
  end)
440
445
  task flag do |_, args|
441
- bundle(flag, opts: args.to_a, banner: true)
446
+ bundle(flag, opts: args.to_a, banner: flag == :exec ? verbose? : true)
442
447
  end
443
448
  when :config
444
- format_desc action, flag, 'list|set|get|unset?,args*'
449
+ format_desc action, flag, 'list|set|get|unset?,opts*,args*'
445
450
  task flag do |_, args|
446
451
  bundle(flag, *args.to_a, banner: true)
447
452
  end
@@ -547,7 +552,7 @@ module Squared
547
552
  end
548
553
  end
549
554
  option('jobs') { |n| cmd << "-j#{n}" if n.to_i > 0 }
550
- run_rb(from: :depend, sync: sync)
555
+ run_rb(sync: sync, from: :depend)
551
556
  end
552
557
  end
553
558
 
@@ -761,41 +766,42 @@ module Squared
761
766
  order = { 'rbenv' => -1, 'rvm' => -1, 'asdf' => -1, 'chruby' => -1 }
762
767
  ENV.fetch('PATH', '').split(':').each_with_index do |val, index|
763
768
  order.each_key do |key|
764
- if val.match?(%r{[/.]#{key}/})
765
- order[key] = index
766
- break
767
- end
769
+ next unless val.match?(%r{[/.]#{key}/})
770
+
771
+ order[key] = index
772
+ break
768
773
  end
769
774
  end
770
- paths = [
771
- "#{ENV.fetch('RBENV_ROOT', '$HOME/.rbenv')}/bin/rbenv",
772
- '$HOME/.rvm/bin/rvm',
773
- @asdf ? "#{ENV.fetch('ASDF_DATA_DIR', '$HOME/.asdf')}/installs/#{@asdf.first}" : nil,
774
- '/usr/bin/rbenv',
775
- '/usr/local/rvm/bin/rvm',
776
- '/usr/share/rvm/bin/rvm',
777
- '/usr/local/share/chruby/chruby.sh'
778
- ].compact
779
- paths.sort do |a, b|
780
- c = -1
781
- d = -1
782
- order.each do |key, val|
783
- pat = %r{/\.?#{key}}
784
- c = val if a.match?(pat)
785
- d = val if b.match?(pat)
786
- end
787
- if c == d
788
- 0
789
- elsif c == -1
790
- 1
791
- elsif d == -1
792
- -1
793
- else
794
- c < d ? -1 : 1
775
+ if @asdf
776
+ [File.join(ENV.fetch('ASDF_DATA_DIR', '$HOME/.asdf'), "installs/#{@asdf.first}")]
777
+ else
778
+ [
779
+ "#{ENV.fetch('RBENV_ROOT', '$HOME/.rbenv')}/bin/rbenv",
780
+ '$HOME/.rvm/bin/rvm',
781
+ '/usr/bin/rbenv',
782
+ '/usr/local/rvm/bin/rvm',
783
+ '/usr/share/rvm/bin/rvm',
784
+ '/usr/local/share/chruby/chruby.sh'
785
+ ].sort do |a, b|
786
+ c = -1
787
+ d = -1
788
+ order.each do |key, val|
789
+ pat = %r{/\.?#{key}}
790
+ c = val if a.match?(pat)
791
+ d = val if b.match?(pat)
792
+ end
793
+ if c == d
794
+ 0
795
+ elsif c == -1
796
+ 1
797
+ elsif d == -1
798
+ -1
799
+ else
800
+ c < d ? -1 : 1
801
+ end
795
802
  end
796
- end
797
- .push('')
798
- .each do |val|
803
+ .push('')
804
+ end.each do |val|
799
805
  next unless val.empty? || File.exist?(val.sub('$HOME', Dir.home))
800
806
 
801
807
  trim = ->(s) { s[/^\D+\d+\.\d+(?:\.\S+)?/, 0].sub(/^([a-z]+)-/i, '\1 ') }
@@ -1064,28 +1070,27 @@ module Squared
1064
1070
  multiple: true, force: false, index: true, border: true).map! { |n| items[n.pred].last }
1065
1071
  end
1066
1072
  unless Array(update).empty?
1067
- cmd = gem_output 'update -f'
1073
+ opts = ['f']
1068
1074
  option('document', prefix: 'gem', ignore: false) do |val|
1069
- cmd << case val
1070
- when '0', 'false'
1071
- '--no-document'
1072
- else
1073
- basic_option 'document', val
1074
- end
1075
+ opts << case val
1076
+ when '0', 'false'
1077
+ 'no-document'
1078
+ else
1079
+ "document=#{val}"
1080
+ end
1075
1081
  end
1076
1082
  option('user-install', prefix: 'gem', ignore: false) do |val|
1077
- cmd << case val
1078
- when '0', 'false'
1079
- '--no-user-install'
1080
- else
1081
- '--user-install'
1082
- end
1083
+ opts << case val
1084
+ when '0', 'false'
1085
+ 'no-user-install'
1086
+ else
1087
+ 'user-install'
1088
+ end
1083
1089
  end
1084
- cmd.merge(update.quote!)
1085
1090
  if filter[:dryrun]
1086
- print_run cmd, false
1091
+ print_run gem_output('update -f', *update.quote!), false
1087
1092
  else
1088
- run(cmd, sync: sync, banner: false, from: :'gem:update')
1093
+ gem(:update, *update, opts: opts)
1089
1094
  end
1090
1095
  end
1091
1096
  print_status(*major, from: :outdated)
@@ -1154,6 +1159,9 @@ module Squared
1154
1159
  end
1155
1160
  op.append(quote: false)
1156
1161
  when :update
1162
+ if !op.arg?('n', 'bindir') && (bin = config_get('bin')) && Dir.exist?(bin)
1163
+ op << quote_option('bindir', bin)
1164
+ end
1157
1165
  if op.arg?('system')
1158
1166
  op.add_first(quote: false) { |val| val if val.match?(SEM_VER) }
1159
1167
  else
@@ -1252,15 +1260,27 @@ module Squared
1252
1260
  when :cache, :check, :clean, :init, :install, :lock, :pack, :package, :platform
1253
1261
  pre = true
1254
1262
  opts.concat(args)
1263
+ when :config
1264
+ if args.empty?
1265
+ pre = true
1266
+ else
1267
+ case (pre = args.shift)
1268
+ when 'list', 'get', 'set', 'unset'
1269
+ cmd << pre
1270
+ else
1271
+ args.unshift(pre)
1272
+ end
1273
+ opts.concat(args)
1274
+ end
1255
1275
  when :doctor
1256
1276
  case (pre = (val = args.shift) || opts.shift)
1257
1277
  when 'diagnose', 'ssl'
1258
1278
  cmd << pre
1259
1279
  else
1260
1280
  if val
1261
- args << val
1281
+ args.unshift(val)
1262
1282
  elsif pre
1263
- opts << pre
1283
+ opts.unshift(pre)
1264
1284
  end
1265
1285
  pre = true
1266
1286
  end
@@ -1280,54 +1300,57 @@ module Squared
1280
1300
  else
1281
1301
  flag
1282
1302
  end),
1283
- cmd, proect: self, no: OPT_BUNDLE[:no][flag], args: flag == :exec)
1303
+ cmd,
1304
+ project: self, no: OPT_BUNDLE[:no][flag], args: flag == :exec || flag == :config)
1284
1305
  op.concat(args) unless pre
1285
1306
  output = false
1286
1307
  invalid = ->(a) { raise_error ArgumentError, "unrecognized args: #{a.join(', ')}", hint: flag }
1287
1308
  case flag
1288
1309
  when :config
1289
- if op.empty?
1290
- op << (val = readline('Enter arguments', force: false))
1291
- output = val.match?(/(?:un)?set/)
1292
- else
1310
+ if pre == 'list'
1311
+ op.clear
1312
+ elsif !op.empty?
1293
1313
  a = op.dup
1294
- b, c, d = op.slice!(0, 3)
1295
- e = op.arg?('global', 'local')
1296
- op << b
1297
- getname = -> { op << (c || readline('Enter name', force: true)) }
1298
- case b
1299
- when 'list'
1300
- nil
1314
+ b, c = op.slice!(0, 2)
1315
+ d = op.arg?('global', 'local')
1316
+ getname = -> { op << (b || readline('Enter name', force: true)) }
1317
+ case pre
1301
1318
  when 'get'
1302
1319
  getname.call
1303
1320
  when 'set'
1304
- if e
1305
- op << c
1306
- c = d
1307
- d = op.shift
1321
+ if d
1322
+ op << b
1323
+ b = c
1324
+ c = op.shift
1308
1325
  end
1309
1326
  getname.call
1310
- op << (d || readline('Enter value', force: true))
1327
+ op << (c || readline('Enter value', force: true))
1311
1328
  output = true
1312
1329
  when 'unset'
1313
- if e
1314
- op << c
1315
- c = d
1330
+ if d
1331
+ op << b
1332
+ b = c
1316
1333
  end
1317
1334
  getname.call
1318
1335
  output = true
1319
1336
  else
1320
- if b
1321
- op << b
1322
- if c
1323
- op.add_quote(c)
1324
- output = true
1325
- end
1337
+ if c && !op.arg?('parseable', 'no-parseable')
1338
+ op.adjoin('set') << b
1339
+ op.add_quote(c)
1340
+ output = true
1341
+ exit 1 unless confirm_basic('Confirm?', op, 'Y')
1342
+ elsif b
1343
+ op.adjoin('get') << b
1344
+ op.unshift(c) if c
1326
1345
  else
1327
1346
  invalid.call(a)
1328
1347
  end
1329
1348
  end
1330
1349
  op.clear
1350
+ else
1351
+ val = readline('Enter arguments', force: false)
1352
+ op << (val.empty? ? 'list' : val)
1353
+ output = val.match?(/^(un)?set/)
1331
1354
  end
1332
1355
  when :plugin
1333
1356
  case plu
@@ -1337,7 +1360,7 @@ module Squared
1337
1360
  op.clear
1338
1361
  end
1339
1362
  when :exec
1340
- if op.empty? || (op.delete(':') && op.append(quote: false))
1363
+ if op.empty? || (op.remove(':') && op.append(quote: false))
1341
1364
  op << readline('Enter arguments', force: true)
1342
1365
  else
1343
1366
  op.append(quote: false)
@@ -1466,6 +1489,12 @@ module Squared
1466
1489
  @gemname ||= ((spec = gemspec) ? spec.name : project)
1467
1490
  end
1468
1491
 
1492
+ def project
1493
+ return @project unless @project.frozen?
1494
+
1495
+ @project = ((spec = gemspec) ? spec.name : @project).dup
1496
+ end
1497
+
1469
1498
  def depend?
1470
1499
  @depend != false && (!@depend.nil? || outdated?)
1471
1500
  end
@@ -1473,7 +1502,17 @@ module Squared
1473
1502
  def copy?
1474
1503
  return true if @copy.is_a?(Hash) ? copy[:into] : super
1475
1504
  return gemdir? if gemdir
1505
+ return false unless @autodetect
1476
1506
 
1507
+ set = lambda do |val, path|
1508
+ base = Pathname.new(path.strip)
1509
+ dir = base + gempath
1510
+ return false unless dir.writable? && base.join(gempath(val, 'specifications')).exist?
1511
+
1512
+ log.warn "using version #{val}".subhint("given #{version}") if version && version != val
1513
+ self.version = val
1514
+ self.gemdir = dir
1515
+ end
1477
1516
  if version
1478
1517
  begin
1479
1518
  case @autodetect
@@ -1484,43 +1523,32 @@ module Squared
1484
1523
  File.join($1, 'lib/ruby/gems', "#{$2}.0")
1485
1524
  end
1486
1525
  when 'asdf'
1487
- pwd_set { `asdf where ruby` }.yield_self do |val|
1526
+ pwd_set { `asdf where ruby`.chomp }.yield_self do |val|
1488
1527
  val =~ /(\d\.\d)\.[^.]+$/ && File.join(val, 'lib/ruby/gems', "#{$1}.0")
1489
1528
  end
1490
1529
  when /bundler?/
1491
- pwd_set { `bundle env` }[/^\s+Gem Path\s+([^#{File::PATH_SEPARATOR}]+)/, 1]
1492
- end.tap { |val| self.gemdir = val if val }
1530
+ pwd_set { `bundle env` }[/^\s+Gem Path\s+(.+)$/, 1].split(File::PATH_SEPARATOR).find do |val|
1531
+ Dir.exist?(File.join(val, 'gems'))
1532
+ end
1533
+ else
1534
+ ENV['GEM_HOME'] || ENV['GEM_ROOT']
1535
+ end.tap do |val|
1536
+ return true if val && set.call(version, val)
1537
+ end
1493
1538
  rescue StandardError => e
1494
1539
  log.debug e
1495
1540
  end
1496
- return true if gemdir?
1497
- end
1498
- return false unless @autodetect
1499
-
1500
- set = lambda do |val, path|
1501
- dir = Pathname.new(path.strip) + gempath
1502
- return false unless dir.writable?
1503
-
1504
- if (ver = version) && ver != val
1505
- log.warn "using version #{val}".subhint("given #{ver}")
1506
- end
1507
- self.version = val
1508
- self.gemdir = dir
1509
- end
1510
- if version
1511
- opt = gempwd
1512
- pwd_set(pass: !opt.nil?) do
1513
- out = `#{gem_output(opt, 'list --local -d', gemname)}`
1514
- next unless out =~ /#{Regexp.escape(gemname)} \(([^)]+)\)/
1541
+ pwd_set(pass: !gempwd.nil?) do
1542
+ out = `#{gem_output(gempwd, 'list --local -d', gemname)}`
1543
+ next unless out =~ /#{Regexp.escape(gemname)}\s+\((.+)\)$/
1515
1544
 
1516
1545
  split_escape($1)
1517
1546
  .unshift(version)
1518
1547
  .uniq
1519
1548
  .each do |val|
1520
- next unless out =~ /\(#{Regexp.escape(val)}[^)]*\):([^\n]+)/
1549
+ next unless out =~ /(?:\(#{Regexp.escape(val)}[^)]*\)|Installed at):\s+(.+)$/
1521
1550
 
1522
- set.call(val, $1)
1523
- return gemdir? if gemdir
1551
+ return gemdir? if set.call(val, $1)
1524
1552
  end
1525
1553
  end
1526
1554
  self.gemdir = Pathname.new(Gem.dir) + gempath
@@ -1600,19 +1628,19 @@ module Squared
1600
1628
  end
1601
1629
 
1602
1630
  def config_get(key)
1603
- ret = if pwd_set { `#{bundle_output('config get --parseable', key)}` } =~ /\A([^=]+)=(.*)\z/ && $1 == key
1604
- $2.chomp
1605
- end
1606
- case ret
1631
+ out = pwd_set { `#{bundle_output('config get --parseable', key)}`.chomp }
1632
+ return unless out =~ /\A([^=]+)=(.*)\z/ && $1 == key
1633
+
1634
+ case (out = $2)
1607
1635
  when 'true'
1608
1636
  true
1609
1637
  when '', '[]'
1610
1638
  nil
1611
1639
  else
1612
- if ret =~ /\A\[:(.+)\]\z/
1613
- $1.split(', :').map! { |val| ((val.delete_prefix!('"') && val.delete_suffix!('"')) || val).to_sym }
1640
+ if out =~ /\A\[:(.+)\]\z/
1641
+ $1.split(', :').map { |val| ((val.delete_prefix!('"') && val.delete_suffix!('"')) || val).to_sym }
1614
1642
  else
1615
- ret || false
1643
+ out || false
1616
1644
  end
1617
1645
  end
1618
1646
  end
@@ -1621,6 +1649,12 @@ module Squared
1621
1649
  run(bundle_output('config', ('--global' if global), 'set', key, *val), banner: false, series: true)
1622
1650
  end
1623
1651
 
1652
+ def unpack_get(tag, ext)
1653
+ return super unless ext == 'gem'
1654
+
1655
+ "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
1656
+ end
1657
+
1624
1658
  def preopts
1625
1659
  verbose? ? ['--verbose'] : []
1626
1660
  end
@@ -1698,9 +1732,9 @@ module Squared
1698
1732
 
1699
1733
  def gemfile
1700
1734
  if @gemfile.nil?
1701
- @gemfile = [project, name].map! { |val| basepath("#{val}.gemspec") }
1702
- .concat(path.glob('*.gemspec'))
1703
- .find(&:exist?) || false
1735
+ @gemfile = [@project, name].map { |val| basepath("#{val}.gemspec") }
1736
+ .concat(path.glob('*.gemspec'))
1737
+ .find(&:exist?) || false
1704
1738
  end
1705
1739
  @gemfile || nil
1706
1740
  end
@@ -1714,8 +1748,10 @@ module Squared
1714
1748
  end
1715
1749
  end
1716
1750
 
1717
- def gempath(val = version)
1718
- File.join('gems', "#{gemname}-#{val}")
1751
+ def gempath(val = version, dir = 'gems')
1752
+ ret = File.join(dir, "#{gemname}-#{val}")
1753
+ ret += '.gemspec' if dir == 'specifications'
1754
+ ret
1719
1755
  end
1720
1756
 
1721
1757
  def gemdir?
@@ -173,9 +173,9 @@ module Squared
173
173
 
174
174
  def_delegators :@target, :+, :-, :<<, :any?, :none?, :include?, :add, :add?, :find, :find_all, :find_index,
175
175
  :merge, :compact, :delete, :delete?, :delete_if, :grep, :grep_v, :inspect, :to_a, :to_s
176
- def_delegators :@extras, :empty?, :each, :each_with_index, :partition, :dup, :first, :shift, :unshift,
177
- :pop, :push, :concat, :index, :join, :detect, :map, :map!, :select, :select!, :slice, :slice!,
178
- :reject, :size
176
+ def_delegators :@extras, :empty?, :member?, :each, :each_with_index, :each_with_object, :partition, :dup,
177
+ :first, :shift, :unshift, :pop, :push, :concat, :index, :join, :detect, :map, :map!, :select,
178
+ :select!, :reject, :slice, :slice!, :size
179
179
 
180
180
  def_delegator :@extras, :delete, :remove
181
181
  def_delegator :@extras, :delete_at, :remove_at
@@ -587,10 +587,12 @@ module Squared
587
587
  elsif exclude.first.is_a?(Symbol)
588
588
  partition(&exclude.first)
589
589
  else
590
+ exclude.map! { |pat| Regexp.new(pat) }
590
591
  partition do |val|
591
- next false if pattern && OptionPartition.pattern?(val)
592
+ val = val.to_s
593
+ next if pattern && OptionPartition.pattern?(val)
592
594
 
593
- exclude.none? { |pat| val.match?(Regexp.new(pat)) }
595
+ exclude.none? { |pat| val.match?(pat) }
594
596
  end
595
597
  end
596
598
  unless temp.empty?
@@ -243,9 +243,8 @@ module Squared
243
243
  true
244
244
  else
245
245
  Common::Prompt.confirm(
246
- "#{log_title(:warn)} \"#{path}\" is not empty. Continue with installation?",
247
- 'N',
248
- force: true, timeout: env('REPO_TIMEOUT', 15, ignore: '0')
246
+ "#{log_title(:warn)} \"#{path}\" is not empty. Continue with installation?", 'N',
247
+ force: true, timeout: env('REPO_TIMEOUT').to_i.yield_self { |n| n > 0 ? n : 15 }
249
248
  )
250
249
  end
251
250
  end
@@ -32,7 +32,10 @@ module Squared
32
32
  end
33
33
  elsif (data = TASK_BATCH[obj])
34
34
  args.each { |ref| data.delete(ref) }
35
- TASK_KEYS.delete(obj) if data.empty?
35
+ if data.empty?
36
+ TASK_KEYS.delete(obj)
37
+ TASK_BATCH.delete(obj)
38
+ end
36
39
  end
37
40
  end
38
41
 
@@ -41,6 +44,7 @@ module Squared
41
44
  obj.each { |key, val| TASK_ALIAS[key][ref] = val }
42
45
  elsif TASK_ALIAS.key?(obj)
43
46
  TASK_ALIAS[obj].delete(ref)
47
+ TASK_ALIAS.delete(obj) if TASK_ALIAS[obj].empty?
44
48
  end
45
49
  end
46
50
 
@@ -243,7 +247,7 @@ module Squared
243
247
  end
244
248
 
245
249
  def exclude?(key, empty = false)
246
- @exclude.include?(key) || (empty && self[key].empty?)
250
+ @exclude.include?(key) || (empty && (!key?(key) || self[key].empty?))
247
251
  end
248
252
 
249
253
  private
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.6.7
4
+ version: 0.6.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  requirements: []
127
- rubygems_version: 3.6.9
127
+ rubygems_version: 4.0.3
128
128
  specification_version: 4
129
129
  summary: Rake task generator for managing multi-language workspaces.
130
130
  test_files: []