squared 0.6.6 → 0.6.8

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: eef895f1332463b52f24d46188726f55878170e90ba8ed9c7dcf1a1fac3bdd41
4
- data.tar.gz: d8ac6097a8ec74b0dd266558ad273e8ea23ba5994f5c79602875e6ce75d7367a
3
+ metadata.gz: f3fd4d34940e2ce81d6aff4d5bb9ccd827c8c11f755808778c0f266fc53fbf00
4
+ data.tar.gz: 4a030838743ef95041fe4cd53a6a4491f9d5a5f89cca6dc1283c04429644cdc1
5
5
  SHA512:
6
- metadata.gz: 8569824e8b5cedbb189666ba9e1b67590887afa004ac43bd5c42cc854cf1a61f51ea5709f16a0c55988cfc7ad5cadab0b4b751ce4864bbb46195f3bc97181248
7
- data.tar.gz: 7f3c48efd9652ee0ad67f5f35bfba87596e6c13f4bb5fb45ebd68aecfb2947e7f43c0ea7dad1bb04e365d45a001d82651e8b59f976274b07e6dda806d0e3bb4c
6
+ metadata.gz: d4e1ddf573b20ea122f1b03d0c7d14ac23542d09aac252ae5eda2185a13a1e42fc32302b82896a6ca07ec6dfcf58dfed81dc3e009f2f7b8c2b8f4ba10fddfe5c
7
+ data.tar.gz: 97bda796bfed20453137241f0f6cd98362d877fccc4674e1a1a0e615f1059ea8067d28a9f1d31e4a96b60c7fbb4011bb58ee05877e47ae3be0c41aea855bc872
data/CHANGELOG.md CHANGED
@@ -1,5 +1,77 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.8] - 2025-12-26
4
+
5
+ ### Added
6
+
7
+ - Ruby attribute project is extracted from Gemspec.
8
+
9
+ ### Changed
10
+
11
+ - Project base task unpack no longer hard codes any extensions.
12
+
13
+ ### Fixed
14
+
15
+ - Gem command outdated did not set bindir with update command.
16
+ - Bundler ultimately never ended up learning how to spell JIT.
17
+
18
+ ## [0.5.20] - 2025-12-26
19
+
20
+ ### Fixed
21
+
22
+ - Bundle config get method did not always discard newline.
23
+
24
+ ## [0.4.34] - 2025-12-26
25
+
26
+ ### Added
27
+
28
+ - Project public base method scope for nested tasks was created.
29
+ - Ruby task copy can autodetect "env" using [GEM_HOME|GEM_ROOT].
30
+
31
+ ### Changed
32
+
33
+ - Python virtual environment did not install poetry during initialization.
34
+
35
+ ### Fixed
36
+
37
+ - Workspace global banner never referenced the correct hash key.
38
+ - Python task depend without editable did not append context directory.
39
+ - Docker task build did not parse DOCKER_OPTIONS as command options.
40
+ - Project base method build did not call Method routines.
41
+ - Bundler autodetect did not check for valid gems directory.
42
+ - Ruby copy to version detection did not check for valid gemspec.
43
+
44
+ ## [0.6.7] - 2025-12-07
45
+
46
+ ### Added
47
+
48
+ - Docker command options were updated to 29.1.
49
+
50
+ ### Fixed
51
+
52
+ - Bundler did not recognize sub-commands options.
53
+ - Project graph did not use built-in comparison method.
54
+
55
+ ## [0.5.19] - 2025-12-07
56
+
57
+ ### Fixed
58
+
59
+ - See `0.4.33`.
60
+
61
+ ## [0.4.33] - 2025-12-07
62
+
63
+ ### Added
64
+
65
+ - Ruby attribute setter gemdir for copy method was created.
66
+ - Project inline run executables binary path are replaced with global alias.
67
+
68
+ ### Fixed
69
+
70
+ - Workspace class Series created non-existent keys when queried.
71
+ - Application class did not support changing base Project class.
72
+ - Git command rev action build did not check build? method.
73
+ - Python command build action python did not use outdir option.
74
+
3
75
  ## [0.6.6] - 2025-11-30
4
76
 
5
77
  ### Added
@@ -1493,6 +1565,8 @@
1493
1565
 
1494
1566
  - Changelog was created.
1495
1567
 
1568
+ [0.6.8]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.8
1569
+ [0.6.7]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.7
1496
1570
  [0.6.6]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.6
1497
1571
  [0.6.5]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.5
1498
1572
  [0.6.4]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.4
@@ -1500,6 +1574,8 @@
1500
1574
  [0.6.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.2
1501
1575
  [0.6.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.1
1502
1576
  [0.6.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.0
1577
+ [0.5.20]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.20
1578
+ [0.5.19]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.19
1503
1579
  [0.5.18]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.18
1504
1580
  [0.5.17]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.17
1505
1581
  [0.5.16]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.16
@@ -1519,6 +1595,8 @@
1519
1595
  [0.5.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.2-ruby
1520
1596
  [0.5.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.1-ruby
1521
1597
  [0.5.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.0-ruby
1598
+ [0.4.34]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.34
1599
+ [0.4.33]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.33
1522
1600
  [0.4.32]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.32
1523
1601
  [0.4.31]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.31
1524
1602
  [0.4.30]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.30
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
@@ -712,7 +712,7 @@ GIT_AUTOSTASH_${NAME}=0 # rebase (project only)
712
712
 
713
713
  ### Docker
714
714
 
715
- * Version: [28.5](https://docs.docker.com/engine/release-notes/28)
715
+ * Version: [29.1](https://docs.docker.com/engine/release-notes/29)
716
716
 
717
717
  ```sh
718
718
  DOCKER_OPTIONS=q,no-cache # all
@@ -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 |
@@ -823,7 +823,7 @@ Features can be enabled through ENV when calling global tasks such as through *C
823
823
  | Command | Flag | ENV |
824
824
  | :--------- | :-------- | :---------------------------------------------------------------- |
825
825
  | depend | - | BINSTUBS=s JOBS=n |
826
- | outdated | - | U|UPDATE=major|minor|patch DRY_RUN |
826
+ | outdated | - | U|UPDATE=major|minor|patch ONLY_EXPLICIT DRY_RUN |
827
827
  | gem | outdated | DOCUMENT=0,1 USER_INSTALL=0,1 |
828
828
  | rbs | prototype | Y=0,1 |
829
829
 
@@ -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
@@ -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
 
@@ -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.6'
4
+ VERSION = '0.6.8'
5
5
  end
@@ -298,9 +298,9 @@ module Squared
298
298
 
299
299
  def pass(name, group: @group, ref: @ref, &blk)
300
300
  data = if group
301
- @pass[:group][group]
301
+ @pass[:group][group.to_s]
302
302
  elsif ref
303
- @pass[:ref][ref]
303
+ @pass[:ref][ref.to_sym]
304
304
  else
305
305
  @pass[:global]
306
306
  end
@@ -359,9 +359,9 @@ module Squared
359
359
  proj = ((if !ref.is_a?(Class)
360
360
  require_project ref
361
361
  Application.find(ref, path: path)
362
- elsif ref < Project::Base
362
+ elsif ref < Application.impl_project
363
363
  ref
364
- end) || @kind[name]&.last || Project::Base).new(self, path, name, **kwargs)
364
+ end) || @kind[name]&.last || Application.impl_project).new(self, path, name, **kwargs)
365
365
  proj.__send__(:index_set, size)
366
366
  @project[name] = proj
367
367
  __get__(:project)[name] = proj unless kwargs[:private]
@@ -606,7 +606,7 @@ module Squared
606
606
  return ret if group && (ret = @banner[:group][group.to_sym])
607
607
 
608
608
  ref.reverse_each { |val| return ret if (ret = @banner[:ref][val]) }
609
- @banner[:ref][:'']
609
+ @banner[:ref][:_]
610
610
  end
611
611
 
612
612
  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'
@@ -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
@@ -537,7 +542,7 @@ module Squared
537
542
  end
538
543
  d = append_hash(d, target: []).join(' ') if d.is_a?(Hash)
539
544
  if a
540
- cmd << [a, d, b].compact.join(' ')
545
+ cmd << [replace_bin(a), d, b].compact.join(' ')
541
546
  else
542
547
  next unless respond_to?(:compose)
543
548
 
@@ -551,7 +556,7 @@ module Squared
551
556
  if cmd
552
557
  return run_b(cmd, sync: sync, from: from) if cmd.is_a?(Proc) || cmd.is_a?(Method)
553
558
 
554
- cmd = as_get cmd, from
559
+ cmd = replace_bin as_get(cmd, from)
555
560
  opts = compose(opts, script: false) if opts && respond_to?(:compose)
556
561
  flags = append_hash(flags, target: []).join(' ') if flags.is_a?(Hash)
557
562
  cmd = case opts
@@ -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
@@ -1358,13 +1371,7 @@ module Squared
1358
1371
  obj.enabled? ? [obj] : []
1359
1372
  else
1360
1373
  workspace.find(group: val, ref: val.to_sym)
1361
- end.sort do |a, b|
1362
- if a.parent == b
1363
- -1
1364
- else
1365
- b.parent == a ? 1 : 0
1366
- end
1367
- end.each do |proj|
1374
+ end.sort.each do |proj|
1368
1375
  next if pass.include?(name = proj.name)
1369
1376
 
1370
1377
  if proj.graph? && !data.key?(name) && !root.include?(name)
@@ -1872,6 +1879,13 @@ module Squared
1872
1879
  ret
1873
1880
  end
1874
1881
 
1882
+ def replace_bin(val)
1883
+ a, b = val.split(' ', 2)
1884
+ return val if val.start_with?(/["']/) || a.include?(File::Separator)
1885
+
1886
+ [shell_bin(a), b].compact.join(' ')
1887
+ end
1888
+
1875
1889
  def parse_json(val, kind: Hash, hint: nil)
1876
1890
  ret = JSON.parse(val)
1877
1891
  raise_error 'invalid JSON'.subhint(kind.name), val, hint: hint if kind && !ret.is_a?(kind)
@@ -2007,7 +2021,9 @@ module Squared
2007
2021
 
2008
2022
  def command(*args, verbose: true)
2009
2023
  out = unless verbose
2010
- [">#{File::NULL}", '2>&1'].tap { |a| a.reverse if File::NULL == 'NUL' }.unshift('').join(' ')
2024
+ cmd = [">#{File::NULL}", '2>&1']
2025
+ cmd.reverse! if File::NULL == 'NUL'
2026
+ cmd.unshift('').join(' ')
2011
2027
  end
2012
2028
  if workspace.powershell?
2013
2029
  "#{shell_bin('powershell.exe')} -Command \"& {#{args.join(' ; ')}}\"#{out}"
@@ -2361,6 +2377,10 @@ module Squared
2361
2377
  (global && @as[from][val]) || val
2362
2378
  end
2363
2379
 
2380
+ def unpack_get(*)
2381
+ nil
2382
+ end
2383
+
2364
2384
  def task_build(keys)
2365
2385
  namespace name do
2366
2386
  ws = workspace
@@ -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 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 network=b no-cache-filter=b o|output=q platform=q
17
17
  q|quiet secret=qq shm-size=b ssh=qq t|tag=b target=b ulimit=q].freeze,
18
18
  bake: %w[print list=q set=q].freeze,
19
19
  shared: %w[check load no-cache pull push allow=q call=b? f|file=p metadata-file=p progress=b provenance=q
@@ -40,22 +40,21 @@ module Squared
40
40
  rm t|tty use-api-socket add-host=q annotation=q a|attach=b blkio-weight=i blkio-weight-device=i
41
41
  cap-add=b cap-drop=b cgroup-parent=b cgroupns=b cidfile=p device=q device-cgroup-rule=q
42
42
  device-read-bps=q device-read-iops=q device-write-bps=q device-write-iops=q
43
- disable-content-trust=b? dns=q dns-option=q dns-search=q domainname=b entrypoint=q e|env=qq
44
- env-file=p expose=q gpus=q group-add=b health-cmd=q health-interval=b health-retries=i
45
- health-start-interval=q health-start-period=q health-timeout=q io-maxbandwidth=b io-maxiops=b
46
- ip=b ip6=q ipc=b isolation=b kernel-memory=b l|label=q label-file=q link=b link-local-ip=q
47
- log-driver=b log-opt=q mac-address=q m|memory=b memory-reservation=b memory-swap=n
48
- memory-swappiness=n mount=qq name=b network=b network-alias=b oom-score-adj=b pid=b pids-limit=n
49
- platform=b p|publish=q pull=b restart=b runtime=b security-opt=q shm-size=b stop-signal=b
50
- stop-timeout=i storage-opt=q sysctl=q tmpfs=q ulimit=q u|user=b userns=b uts=b v|volume=q
51
- volume-driver=b volumes-from=b w|workdir=q].freeze,
52
- run: %w[d|detach detach-keys=q hostname=q sig-proxy=b?].freeze,
43
+ dns=q dns-option=q dns-search=q domainname=b entrypoint=q e|env=qq env-file=p expose=q gpus=q
44
+ group-add=b health-cmd=q health-interval=b health-retries=i health-start-interval=q
45
+ health-start-period=q health-timeout=q hostname=q io-maxbandwidth=b io-maxiops=b ip=b ip6=q ipc=b
46
+ isolation=b l|label=q label-file=q link=b link-local-ip=q log-driver=b log-opt=q mac-address=q
47
+ m|memory=b memory-reservation=b memory-swap=n memory-swappiness=n mount=qq name=b network=b
48
+ network-alias=b oom-score-adj=b pid=b pids-limit=n platform=q p|publish=q pull=b restart=b
49
+ runtime=b security-opt=q shm-size=b stop-signal=b stop-timeout=i storage-opt=q sysctl=q tmpfs=q
50
+ ulimit=q u|user=b userns=b uts=b v|volume=q volume-driver=b volumes-from=b w|workdir=q].freeze,
51
+ run: %w[d|detach detach-keys=q sig-proxy=b?].freeze,
53
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
54
- cpuset-cpus=b cpuset-mems=b m|memory=b memory-reservation=b memory-swap=b pids-limit=n
53
+ cpuset-cpus=b cpuset-mems=b m|memory=b memory-reservation=b memory-swap=n pids-limit=n
55
54
  restart=q].freeze,
56
- exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p user=e
55
+ exec: %w[d|detach i|interactive privileged t|tty detach-keys=q e|env=qq env-file=p u|user=e
57
56
  w|workdir=q].freeze,
58
- commit: %w[a|author=q c|change=q m|message=q pause=b?].freeze,
57
+ commit: %w[no-pause a|author=q c|change=q m|message=q pause=b?].freeze,
59
58
  inspect: %w[s|size f|format=q type=b].freeze,
60
59
  start: %w[a|attach i|interactive detach-keys=q].freeze,
61
60
  stop: %w[s|signal=b t|timeout=i].freeze,
@@ -65,9 +64,9 @@ module Squared
65
64
  }.freeze,
66
65
  image: {
67
66
  ls: %w[a|all digests no-trunc q|quiet tree f|filter=q format=q].freeze,
68
- push: %w[a|all-tags disable-content-trust=b? platform=b q|quiet].freeze,
69
- rm: %w[f|force no-prune platform=b].freeze,
70
- save: %w[o|output=p platform=b].freeze
67
+ push: %w[a|all-tags platform=q q|quiet].freeze,
68
+ rm: %w[f|force no-prune platform=q].freeze,
69
+ save: %w[o|output=p platform=q].freeze
71
70
  }.freeze,
72
71
  network: {
73
72
  connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=q link=b link-local-ip=q].freeze,
@@ -324,21 +323,20 @@ module Squared
324
323
  def compose(opts, flags = nil, script: false, args: nil, from: :run, **)
325
324
  return opts unless script
326
325
 
327
- ret = docker_session
328
326
  if from == :run
329
327
  if bake?(n = filetype)
330
- ret << 'buildx bake'
328
+ ret = docker_session 'buildx bake'
331
329
  append_file n
332
330
  from = :bake
333
331
  elsif compose?(n)
334
- ret << 'compose build'
332
+ ret = docker_session 'compose build'
335
333
  append_file n
336
334
  from = :compose
337
335
  else
338
- ret << 'build'
336
+ ret = docker_session 'build'
339
337
  end
340
338
  else
341
- ret << from
339
+ ret = docker_session from
342
340
  end
343
341
  case opts
344
342
  when String
@@ -883,6 +883,8 @@ module Squared
883
883
  rev_parse(flag, ref: ref, size: size)
884
884
  end
885
885
  when :build
886
+ next unless build?
887
+
886
888
  format_desc action, flag, 'opts*'
887
889
  task flag do |_, args|
888
890
  revbuild flag, args.to_a
@@ -1908,8 +1910,8 @@ module Squared
1908
1910
  return args ? [IO.popen(cmd), banner || '', from] : IO.popen(cmd)
1909
1911
  elsif stdin? ? sync : stdout
1910
1912
  print_item banner unless multiple
1911
- ret = `#{cmd}`
1912
- raise(ret.chomp.empty? ? $?.to_s : ret) unless $?.success?
1913
+ ret = `#{cmd}`.chomp
1914
+ raise(ret.empty? ? $?.to_s : ret) unless $?.success?
1913
1915
 
1914
1916
  if ret.empty?
1915
1917
  success?(nil, !banner.nil?)
@@ -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')
@@ -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,
@@ -101,7 +101,7 @@ module Squared
101
101
 
102
102
  attr_reader :venv, :editable
103
103
 
104
- def initialize(*, editable: '.', verbose: nil, asdf: 'python', **kwargs)
104
+ def initialize(*, editable: '.', asdf: 'python', **kwargs)
105
105
  super
106
106
  if @pass.include?(Python.ref)
107
107
  initialize_ref Python.ref
@@ -344,7 +344,7 @@ module Squared
344
344
  when :poetry then 'output?'
345
345
  when :pdm then 'dest?'
346
346
  when :hatch then 'location?'
347
- else 'srcdir?'
347
+ else 'outdir?,srcdir?'
348
348
  end)
349
349
  task flag do |_, args|
350
350
  build! flag, args.to_a
@@ -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
@@ -582,36 +583,27 @@ module Squared
582
583
  cmd, opts = python_session('-m build', opts: opts)
583
584
  OPT_PYTHON[:build]
584
585
  end
585
- srcdir = nil
586
586
  op = OptionPartition.new(opts, list, cmd, project: self, single: singleopt(flag))
587
- op.each do |opt|
588
- if !srcdir && exist?(opt.chomp('*')) && projectpath?(opt.chomp('*'))
589
- srcdir = opt
590
- else
591
- op.found << opt
592
- end
593
- end
594
- op.swap
595
587
  case flag
596
- when :poetry, :pdm
597
- if srcdir
598
- args = flag == :pdm ? %w[d dest] : %w[o output]
599
- if op.arg?(*args)
600
- op.push(srcdir)
601
- else
602
- op << quote_option(args.last, basepath(srcdir))
603
- end
604
- srcdir = nil
605
- end
606
588
  when :hatch
607
- if ENV['HATCH_BUILD_LOCATION']
608
- srcdir = nil
609
- else
610
- srcdir ||= path
589
+ if !ENV['HATCH_BUILD_LOCATION'] && (outdir ||= op.shift)
590
+ op.add_path(outdir)
591
+ end
592
+ else
593
+ unless op.empty?
594
+ args = case flag
595
+ when :poetry
596
+ %w[o output]
597
+ when :pdm
598
+ %w[d dest]
599
+ else
600
+ srcdir = true
601
+ %w[o outdir]
602
+ end
603
+ op << quote_option(args.last, basepath(op.shift)) unless op.arg?(*args)
611
604
  end
612
- op << basic_option('p', project) unless ENV['HATCH_PROJECT'] || op.arg?('p', 'project')
613
605
  end
614
- op.add_path(srcdir) if srcdir
606
+ op.exist?(add: true, first: true) if srcdir
615
607
  op.clear
616
608
  run(from: :"#{flag}:build")
617
609
  end
@@ -770,17 +762,21 @@ module Squared
770
762
  end
771
763
  case key
772
764
  when :dependfile
773
- val = basepath(*args)
774
- if (index = DEP_PYTHON.index(val.basename.to_s))
775
- @dependindex = index
776
- @dependfile = val
765
+ if args.first.nil?
766
+ super
777
767
  else
778
- 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
779
775
  end
780
776
  when :editable
781
777
  editable_set args.first
782
778
  when :venv
783
- instance_variable_set(:"@#{key}", (basepath(*args) unless args.empty?))
779
+ @venv = args.empty? || args.first.nil? ? nil : basepath(*args)
784
780
  else
785
781
  super
786
782
  end
@@ -805,10 +801,11 @@ module Squared
805
801
  end
806
802
 
807
803
  def python_session(*cmd, opts: nil)
808
- 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
809
806
 
810
807
  op = OptionPartition.new(opts, OPT_PYTHON[:common], project: self, single: singleopt(:python))
811
- [session('python', *op.to_a, *cmd, path: venv.nil?), op.extras]
808
+ [session('python', *pre, *op.to_a, *cmd, path: venv.nil?), op.extras]
812
809
  end
813
810
 
814
811
  def poetry_session(*cmd)
@@ -828,8 +825,8 @@ module Squared
828
825
  def create_session(*cmd, name:, common:, opts: nil)
829
826
  return session(name, *preopts, *cmd, path: venv.nil?) unless opts
830
827
 
831
- op = OptionPartition.new(opts, common, project: self, single: singleopt)
832
- [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]
833
830
  end
834
831
 
835
832
  def append_pip(flag, opts, target: @session, from: nil)
@@ -885,14 +882,16 @@ module Squared
885
882
  OptionPartition.delete_key(target, 'e', 'editable')
886
883
  case val
887
884
  when '0', 'false'
888
- return
885
+ return unless installable?
889
886
  else
890
887
  val = basepath val
891
888
  end
892
- elsif session_arg?('e', 'editable', target: target) || !(val = editable)
889
+ elsif session_arg?('e', 'editable', target: target) || !installable?
893
890
  return
891
+ else
892
+ val = editable
894
893
  end
895
- target << quote_option('e', basepath(val))
894
+ target << (val ? quote_option('e', basepath(val)) : '.')
896
895
  end
897
896
 
898
897
  def append_global(target: @session)
@@ -1071,9 +1070,9 @@ module Squared
1071
1070
  status = op.append(dir, delim: true)
1072
1071
  .clear(pass: false)
1073
1072
  .arg?(/\A-v+\z/)
1074
- success?(run(op, env, exception: true, banner: banner), banner, !status) do |ret|
1075
- puts(ret && dir.directory? ? "Success: #{dir}" : 'Failed')
1076
- 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') }
1077
1076
  end
1078
1077
 
1079
1078
  def pip_install?(flag)
@@ -41,6 +41,7 @@ module Squared
41
41
  common: %w[no-color V|verbose r|retry=i].freeze,
42
42
  common_all: %w[all all-platforms path=p].freeze,
43
43
  common_git: %w[branch=q git=q path=p ref=q].freeze,
44
+ common_version: %w[local major minor patch pre strict].freeze,
44
45
  add: %w[optimistic quiet skip-install strict github=q glob=q g|group=q require=q s|source=q
45
46
  v|version=q].freeze,
46
47
  binstubs: %w[force standalone shebang=q].freeze,
@@ -48,25 +49,27 @@ module Squared
48
49
  check: %w[dry-run gemfile=p path=p].freeze,
49
50
  clean: %w[dry-run force].freeze,
50
51
  config: %w[global local].freeze,
51
- doctor: %w[quiet gemfile=p].freeze,
52
+ doctor: %w[quiet ssl gemfile=p].freeze,
53
+ doctor_ssl: %w[host=q tls-version=b verify-mode=b].freeze,
52
54
  exec: %w[gemfile=p].freeze,
53
55
  gem: %w[b|bin git no-exe rubocop ci=b e|edit=p? ext=b github-username=q linter=b t|test=b?].freeze,
54
56
  init: %w[gemfile=p gemspec=p].freeze,
55
57
  install: %w[frozen no-cache no-prune system binstubs=p? path=p standalone=q? target-rbconfig=p trust-policy=b
56
58
  with=q without=q].freeze,
57
- install_a: %w[force full-index quiet redownload gemfile=p j|jobs=i].freeze,
58
- lock: %w[add-checksums conservative full-index local major minor normalize-platforms patch pre print strict
59
- add-platform=q bundler=b? gemfile=p lockfile=p remove-platform=p update=q?].freeze,
59
+ install_a: %w[force full-index local quiet redownload gemfile=p j|jobs=i].freeze,
60
+ lock: %w[add-checksums conservative full-index normalize-platforms print add-platform=q bundler=b? gemfile=p
61
+ lockfile=p remove-platform=p update=q?].freeze,
60
62
  open: %w[path=p].freeze,
61
- outdated: %w[filter-major filter-minor filter-patch groups local parseable pre only-explicit strict
63
+ outdated: %w[filter-major filter-minor filter-patch filter-strict groups parseable porcelain only-explicit
62
64
  update-strict group=q source=q].freeze,
63
65
  platform: %w[ruby].freeze,
64
66
  plugin: %w[source=q version=q].freeze,
67
+ plugin_uninstall: %w[all].freeze,
65
68
  remove: %w[install].freeze,
66
69
  show: %w[outdated paths].freeze,
67
70
  update: %w[all conservative local major minor patch pre ruby strict bundler=b? g|group=q source=q].freeze,
68
71
  no: {
69
- gem: %w[changelog ci coc linter mit test].freeze
72
+ gem: %w[changelog ci coc exe linter mit test].freeze
70
73
  }.freeze
71
74
  }.freeze
72
75
  OPT_GEM = {
@@ -79,8 +82,8 @@ module Squared
79
82
  cert: %w[a|add=p b|build=q C|certificate=p d|days=i l|list=q A|key-algorithm=b K|private-key=p r|remove=q
80
83
  R|re-sign s|sign=p].freeze,
81
84
  check: %w[a v|version=q].freeze,
82
- cleanup: %w[n d|dry-run].freeze,
83
- contents: %w[l all s|spec-dir=p v|version=q].freeze,
85
+ cleanup: %w[D n d|dry-run].freeze,
86
+ contents: %w[l all s|spec-dir=q v|version=q].freeze,
84
87
  dependency: %w[R pipe platform=q v|version=q].freeze,
85
88
  exec: %w[conservative g|gem=b v|version=q].freeze,
86
89
  fetch: %w[clear-sources platform=q v|version=q].freeze,
@@ -89,11 +92,11 @@ module Squared
89
92
  install: %w[v|version=q].freeze,
90
93
  install_a: %w[E f w conservative default development development-all explain ignore-dependencies N|no-document
91
94
  vendor n|bindir=p build-root=p document=b? g|file=p? i|install-dir=p platform=q
92
- target-rbconfig=p? P|trust-policy=b without=b].freeze,
95
+ target-rbconfig=p? P|trust-policy=b without=q].freeze,
93
96
  list: %w[d i I].freeze,
94
97
  lock: %w[s].freeze,
95
98
  open: %w[e|editor=p v|version=q].freeze,
96
- outdated: %w[C=p platform=q].freeze,
99
+ outdated: %w[platform=q].freeze,
97
100
  owner: %w[a|add=q r|remove=q p|http-proxy=q?].freeze,
98
101
  pristine: %w[E all only-executables only-missing-extensions only-plugins n|bindir=p i|install-dir=p skip=b
99
102
  v|version=q].freeze,
@@ -113,7 +116,7 @@ module Squared
113
116
  check: %w[alien doctor dry-run gems].freeze,
114
117
  cleanup: %w[check-development user-install].freeze,
115
118
  contents: %w[lib-only prefix show-install-dir].freeze,
116
- dependency: %w[http-proxy reverse-dependencies].freeze,
119
+ dependency: %w[http-proxy prerelease reverse-dependencies].freeze,
117
120
  exec: %w[prerelease].freeze,
118
121
  fetch: %w[http-proxy prerelease suggestions].freeze,
119
122
  generate_index: %w[compact modern].freeze,
@@ -220,6 +223,10 @@ module Squared
220
223
  end
221
224
  end
222
225
 
226
+ def project=(val)
227
+ @project = val.dup
228
+ end
229
+
223
230
  def gemdir=(val)
224
231
  @gemdir = if val.is_a?(Pathname)
225
232
  val
@@ -381,7 +388,7 @@ module Squared
381
388
  flags.each do |flag|
382
389
  case action
383
390
  when 'outdated'
384
- format_desc action, flag, "#{shortname('i', 's', 'u', 'd')},opts*"
391
+ format_desc action, flag, "#{shortname('i', 's', 'u', 'd')},e/xplicit,opts*"
385
392
  task flag do |_, args|
386
393
  outdated flag, args.to_a
387
394
  end
@@ -585,6 +592,7 @@ module Squared
585
592
  se = has_value!(opts, 's', 'select')
586
593
  ia = has_value!(opts, 'i', 'interactive') && !se
587
594
  up = has_value!(opts, 'u', 'update')
595
+ opts << 'only-explicit' if has_value!(opts, 'e', 'explicit')
588
596
  dryrun = has_value!(opts, 'd', 'dry-run')
589
597
  if !sync || stdin?
590
598
  se = false
@@ -603,6 +611,7 @@ module Squared
603
611
  end
604
612
  items = []
605
613
  end
614
+ cmd << '--only-explicit' if option('only-explicit', prefix: 'bundle')
606
615
  dryrun ||= dryrun?(prefix: 'bundle')
607
616
  log.info cmd.to_s
608
617
  on :first, :outdated
@@ -908,7 +917,8 @@ module Squared
908
917
  when :build, :cert, :generate_index, :mirror, :outdated, :push, :server, :signin, :signout, :sources, :stale
909
918
  opts.concat(args)
910
919
  end
911
- op = OptionPartition.new(opts, gemopts(flag), gem_session(flag), project: self, no: OPT_GEM[:no][flag])
920
+ op = OptionPartition.new(opts, gemopts(flag), gem_session(flag),
921
+ project: self, no: OPT_GEM[:no][flag == :update ? :install : flag])
912
922
  from = :"gem:#{flag}"
913
923
  if flag == :outdated
914
924
  op.adjoin(gempwd, start: 0) if gempwd
@@ -1058,28 +1068,27 @@ module Squared
1058
1068
  multiple: true, force: false, index: true, border: true).map! { |n| items[n.pred].last }
1059
1069
  end
1060
1070
  unless Array(update).empty?
1061
- cmd = gem_output 'update -f'
1071
+ opts = ['f']
1062
1072
  option('document', prefix: 'gem', ignore: false) do |val|
1063
- cmd << case val
1064
- when '0', 'false'
1065
- '--no-document'
1066
- else
1067
- basic_option 'document', val
1068
- end
1073
+ opts << case val
1074
+ when '0', 'false'
1075
+ 'no-document'
1076
+ else
1077
+ "document=#{val}"
1078
+ end
1069
1079
  end
1070
1080
  option('user-install', prefix: 'gem', ignore: false) do |val|
1071
- cmd << case val
1072
- when '0', 'false'
1073
- '--no-user-install'
1074
- else
1075
- '--user-install'
1076
- end
1081
+ opts << case val
1082
+ when '0', 'false'
1083
+ 'no-user-install'
1084
+ else
1085
+ 'user-install'
1086
+ end
1077
1087
  end
1078
- cmd.merge(update.quote!)
1079
1088
  if filter[:dryrun]
1080
- print_run cmd, false
1089
+ print_run gem_output('update -f', *update.quote!), false
1081
1090
  else
1082
- run(cmd, sync: sync, banner: false, from: :'gem:update')
1091
+ gem(:update, *update, opts: opts)
1083
1092
  end
1084
1093
  end
1085
1094
  print_status(*major, from: :outdated)
@@ -1148,6 +1157,9 @@ module Squared
1148
1157
  end
1149
1158
  op.append(quote: false)
1150
1159
  when :update
1160
+ if !op.arg?('n', 'bindir') && (bin = config_get('bin')) && Dir.exist?(bin)
1161
+ op << quote_option('bindir', bin)
1162
+ end
1151
1163
  if op.arg?('system')
1152
1164
  op.add_first(quote: false) { |val| val if val.match?(SEM_VER) }
1153
1165
  else
@@ -1240,13 +1252,41 @@ module Squared
1240
1252
  end
1241
1253
  end
1242
1254
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1255
+ invalid = ->(a) { raise_error ArgumentError, "unrecognized args: #{a.join(', ')}", hint: flag }
1256
+ cmd = bundle_session(flag)
1243
1257
  case flag
1244
- when :cache, :check, :clean, :doctor, :init, :install, :lock, :pack, :package, :platform
1258
+ when :cache, :check, :clean, :init, :install, :lock, :pack, :package, :platform
1245
1259
  pre = true
1246
1260
  opts.concat(args)
1261
+ when :doctor
1262
+ case (pre = (val = args.shift) || opts.shift)
1263
+ when 'diagnose', 'ssl'
1264
+ cmd << pre
1265
+ else
1266
+ if val
1267
+ args << val
1268
+ elsif pre
1269
+ opts << pre
1270
+ end
1271
+ pre = true
1272
+ end
1273
+ opts.concat(args)
1274
+ when :plugin
1275
+ case (plu = args.shift || opts.shift)
1276
+ when 'install', 'uninstall', 'help', 'list'
1277
+ cmd << plu
1278
+ else
1279
+ invalid.call(plu)
1280
+ end
1247
1281
  end
1248
- op = OptionPartition.new(opts, bundleopts(flag), bundle_session(flag),
1249
- project: self, no: OPT_BUNDLE[:no][flag], args: flag == :exec)
1282
+ op = OptionPartition.new(opts, bundleopts(if pre == 'ssl'
1283
+ :doctor_ssl
1284
+ elsif plu
1285
+ plu == 'install' ? :plugin : :"plugin_#{plu}"
1286
+ else
1287
+ flag
1288
+ end),
1289
+ cmd, project: self, no: OPT_BUNDLE[:no][flag], args: flag == :exec)
1250
1290
  op.concat(args) unless pre
1251
1291
  output = false
1252
1292
  invalid = ->(a) { raise_error ArgumentError, "unrecognized args: #{a.join(', ')}", hint: flag }
@@ -1296,18 +1336,14 @@ module Squared
1296
1336
  op.clear
1297
1337
  end
1298
1338
  when :plugin
1299
- a = op.dup
1300
- case (b = op.shift)
1339
+ case plu
1301
1340
  when 'install', 'uninstall', 'help'
1302
1341
  op.append
1303
- when 'list'
1304
- op.clear
1305
1342
  else
1306
- invalid.call(a)
1343
+ op.clear
1307
1344
  end
1308
- op.adjoin(b, with: 'plugin')
1309
1345
  when :exec
1310
- if op.empty? || (op.delete(':') && op.append(quote: false))
1346
+ if op.empty? || (op.remove(':') && op.append(quote: false))
1311
1347
  op << readline('Enter arguments', force: true)
1312
1348
  else
1313
1349
  op.append(quote: false)
@@ -1436,6 +1472,12 @@ module Squared
1436
1472
  @gemname ||= ((spec = gemspec) ? spec.name : project)
1437
1473
  end
1438
1474
 
1475
+ def project
1476
+ return @project unless @project.frozen?
1477
+
1478
+ @project = ((spec = gemspec) ? spec.name : @project).dup
1479
+ end
1480
+
1439
1481
  def depend?
1440
1482
  @depend != false && (!@depend.nil? || outdated?)
1441
1483
  end
@@ -1457,8 +1499,12 @@ module Squared
1457
1499
  pwd_set { `asdf where ruby` }.yield_self do |val|
1458
1500
  val =~ /(\d\.\d)\.[^.]+$/ && File.join(val, 'lib/ruby/gems', "#{$1}.0")
1459
1501
  end
1502
+ when 'env'
1503
+ ENV['GEM_HOME'] || ENV['GEM_ROOT']
1460
1504
  when /bundler?/
1461
- pwd_set { `bundle env` }[/^\s+Gem Path\s+([^#{File::PATH_SEPARATOR}]+)/, 1]
1505
+ pwd_set { `bundle env` }[/^\s+Gem Path\s+(.+)$/, 1].split(File::PATH_SEPARATOR).find do |val|
1506
+ Dir.exist?(val)
1507
+ end
1462
1508
  end.tap { |val| self.gemdir = val if val }
1463
1509
  rescue StandardError => e
1464
1510
  log.debug e
@@ -1468,12 +1514,11 @@ module Squared
1468
1514
  return false unless @autodetect
1469
1515
 
1470
1516
  set = lambda do |val, path|
1471
- dir = Pathname.new(path.strip) + gempath
1472
- return false unless dir.writable?
1517
+ base = Pathname.new(path.strip)
1518
+ dir = base + gempath
1519
+ return false unless dir.writable? && base.join(gempath(val, 'specification')).exist?
1473
1520
 
1474
- if (ver = version) && ver != val
1475
- log.warn "using version #{val}".subhint("given #{ver}")
1476
- end
1521
+ log.warn "using version #{val}".subhint("given #{version}") if version && version != val
1477
1522
  self.version = val
1478
1523
  self.gemdir = dir
1479
1524
  end
@@ -1481,16 +1526,15 @@ module Squared
1481
1526
  opt = gempwd
1482
1527
  pwd_set(pass: !opt.nil?) do
1483
1528
  out = `#{gem_output(opt, 'list --local -d', gemname)}`
1484
- next unless out =~ /#{Regexp.escape(gemname)} \(([^)]+)\)/
1529
+ next unless out =~ /#{Regexp.escape(gemname)}\s+\((.+)\)$/
1485
1530
 
1486
1531
  split_escape($1)
1487
1532
  .unshift(version)
1488
1533
  .uniq
1489
1534
  .each do |val|
1490
- next unless out =~ /\(#{Regexp.escape(val)}[^)]*\):([^\n]+)/
1535
+ next unless out =~ /(?:\(#{Regexp.escape(val)}[^)]*\)|Installed at):\s+(.+)$/
1491
1536
 
1492
- set.call(val, $1)
1493
- return gemdir? if gemdir
1537
+ return gemdir? if set.call(val, $1)
1494
1538
  end
1495
1539
  end
1496
1540
  self.gemdir = Pathname.new(Gem.dir) + gempath
@@ -1570,19 +1614,19 @@ module Squared
1570
1614
  end
1571
1615
 
1572
1616
  def config_get(key)
1573
- ret = if pwd_set { `#{bundle_output('config get --parseable', key)}` } =~ /\A([^=]+)=(.*)\z/ && $1 == key
1574
- $2.chomp
1575
- end
1576
- case ret
1617
+ out = pwd_set { `#{bundle_output('config get --parseable', key)}`.chomp }
1618
+ return unless out =~ /\A([^=]+)=(.*)\z/ && $1 == key
1619
+
1620
+ case (out = $2)
1577
1621
  when 'true'
1578
1622
  true
1579
1623
  when '', '[]'
1580
1624
  nil
1581
1625
  else
1582
- if ret =~ /\A\[:(.+)\]\z/
1583
- $1.split(', :').map! { |val| ((val.delete_prefix!('"') && val.delete_suffix!('"')) || val).to_sym }
1626
+ if out =~ /\A\[:(.+)\]\z/
1627
+ $1.split(', :').map { |val| ((val.delete_prefix!('"') && val.delete_suffix!('"')) || val).to_sym }
1584
1628
  else
1585
- ret || false
1629
+ out || false
1586
1630
  end
1587
1631
  end
1588
1632
  end
@@ -1591,6 +1635,12 @@ module Squared
1591
1635
  run(bundle_output('config', ('--global' if global), 'set', key, *val), banner: false, series: true)
1592
1636
  end
1593
1637
 
1638
+ def unpack_get(tag, ext)
1639
+ return super unless ext == 'gem'
1640
+
1641
+ "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
1642
+ end
1643
+
1594
1644
  def preopts
1595
1645
  verbose? ? ['--verbose'] : []
1596
1646
  end
@@ -1634,6 +1684,8 @@ module Squared
1634
1684
  args << :common_git
1635
1685
  when :binstubs, :cache
1636
1686
  args << :common_all
1687
+ when :lock, :outdated
1688
+ args << :common_version
1637
1689
  end
1638
1690
  OPT_BUNDLE[:common] + args.flat_map { |name| OPT_BUNDLE.fetch(name, []) }
1639
1691
  end
@@ -1666,9 +1718,9 @@ module Squared
1666
1718
 
1667
1719
  def gemfile
1668
1720
  if @gemfile.nil?
1669
- @gemfile = [project, name].map! { |val| basepath("#{val}.gemspec") }
1670
- .concat(path.glob('*.gemspec'))
1671
- .find(&:exist?) || false
1721
+ @gemfile = [@project, name].map { |val| basepath("#{val}.gemspec") }
1722
+ .concat(path.glob('*.gemspec'))
1723
+ .find(&:exist?) || false
1672
1724
  end
1673
1725
  @gemfile || nil
1674
1726
  end
@@ -1682,8 +1734,10 @@ module Squared
1682
1734
  end
1683
1735
  end
1684
1736
 
1685
- def gempath(val = version)
1686
- File.join('gems', "#{gemname}-#{val}")
1737
+ def gempath(val = version, dir = 'gems')
1738
+ ret = File.join(dir, "#{gemname}-#{val}")
1739
+ ret += '.gemspec' if dir == 'specifications'
1740
+ ret
1687
1741
  end
1688
1742
 
1689
1743
  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
@@ -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,15 +32,19 @@ 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
 
39
42
  def alias(ref, obj)
40
43
  if obj.is_a?(Hash)
41
44
  obj.each { |key, val| TASK_ALIAS[key][ref] = val }
42
- else
43
- TASK_ALIAS[obj]&.delete(ref)
45
+ elsif TASK_ALIAS.key?(obj)
46
+ TASK_ALIAS[obj].delete(ref)
47
+ TASK_ALIAS.delete(obj) if TASK_ALIAS[obj].empty?
44
48
  end
45
49
  end
46
50
 
@@ -176,6 +180,8 @@ module Squared
176
180
  end
177
181
 
178
182
  def alias_get(key)
183
+ return unless TASK_ALIAS.key?(key)
184
+
179
185
  TASK_ALIAS[key]
180
186
  end
181
187
 
@@ -193,10 +199,10 @@ module Squared
193
199
  end
194
200
 
195
201
  def extend?(obj, key)
196
- return false unless (items = TASK_EXTEND[key])
202
+ return false unless TASK_EXTEND.key?(key)
197
203
 
198
204
  ret = false
199
- items.each do |kind|
205
+ TASK_EXTEND[key].each do |kind|
200
206
  next unless obj.is_a?(kind)
201
207
 
202
208
  meth = :"#{key}?"
@@ -241,7 +247,7 @@ module Squared
241
247
  end
242
248
 
243
249
  def exclude?(key, empty = false)
244
- @exclude.include?(key) || (empty && self[key].empty?)
250
+ @exclude.include?(key) || (empty && (!key?(key) || self[key].empty?))
245
251
  end
246
252
 
247
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.6
4
+ version: 0.6.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham