legionio 1.6.2 → 1.6.3

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: 49e219b9a9c790b6ec63903daee3a26194a5a1611cccd0013a05bb7a34a3d7c9
4
- data.tar.gz: eedbb6e81c2ba386cee0718eb3aed307a021d25959579bb2a02c8bd011ca4fa5
3
+ metadata.gz: 72cd45444eead02f6fe56c876cc25c42c4f74111beaf76e5d898cbe94dbf2ea6
4
+ data.tar.gz: f9f69b056a77e373eff39813f96f79882509dfdf7273bc81afee92dc556d84f6
5
5
  SHA512:
6
- metadata.gz: 141f1ad15ae3595a411e4e1ddaf7fa4544bd1fd5aa23be7425574e783a55581773d0a860ace1d7f6dce97bf3004b6fc42998374cdfe8b3555b01547e98be5f1e
7
- data.tar.gz: a05b2f2cb76d9237dc785b396af6f72b03657866ba4f57fd9b7673594d3212634e9c920d90529c5134544cbdb8d32e9994b188e155366f6f69f7df803355dc90
6
+ metadata.gz: e86e061031320558c96fddc8bfabf2380a97cd51ee27a87d61cd7758e7cb432f8dc2b45257447146ad93ba16f4fd7100de3a90b2f3ecb95d41535a08efaf53af
7
+ data.tar.gz: 40420f889daf45ddf2f75533e981063b33501423ae330e59114b40dfff899e345c1deeb82c9244183842c78a952b9ad1a39d9b10ad54056afd3a7f7b3a59f0ec
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Legion Changelog
2
2
 
3
+ ## [1.6.3] - 2026-03-26
4
+
5
+ ### Changed
6
+ - `legionio update` now uses `gem outdated` instead of custom HTTP client to check rubygems.org
7
+ - Remove `concurrent-ruby`, `net/http`, `json` dependencies from update command
8
+ - 4 persistent keep-alive connections replaced by single `gem outdated` call (~8s, 100% reliable)
9
+
3
10
  ## [1.6.2] - 2026-03-26
4
11
 
5
12
  ### Fixed
@@ -3,9 +3,6 @@
3
3
  require 'English'
4
4
  require 'thor'
5
5
  require 'rbconfig'
6
- require 'concurrent'
7
- require 'net/http'
8
- require 'json'
9
6
  require 'rubygems/uninstaller'
10
7
 
11
8
  module Legion
@@ -81,83 +78,60 @@ module Legion
81
78
 
82
79
  def update_gems(gem_names, gem_bin, dry_run: false)
83
80
  local_versions = snapshot_versions(gem_names)
84
- remote_versions = fetch_remote_versions_parallel(gem_names)
81
+ outdated_map = fetch_outdated(gem_bin, gem_names)
85
82
 
86
- outdated = gem_names.select do |name|
87
- remote = remote_versions[name]
88
- local = local_versions[name]
89
- remote && local && Gem::Version.new(remote) > Gem::Version.new(local)
83
+ results = gem_names.map do |name|
84
+ info = outdated_map[name]
85
+ if info
86
+ { name: name, from: local_versions[name], to: info[:remote], status: dry_run ? 'available' : 'pending' }
87
+ else
88
+ { name: name, from: local_versions[name], status: 'current' }
89
+ end
90
90
  end
91
91
 
92
- return dry_run_results(gem_names, local_versions, remote_versions, outdated) if dry_run
92
+ return results if dry_run
93
93
 
94
- return current_results(gem_names, remote_versions) if outdated.empty?
94
+ pending = results.select { |r| r[:status] == 'pending' }
95
+ return results.each { |r| r[:status] = 'current' if r[:status] == 'pending' } if pending.empty?
95
96
 
96
- install_results(gem_names, gem_bin, remote_versions, outdated)
97
+ install_outdated(gem_bin, pending, results)
97
98
  end
98
99
 
99
- def dry_run_results(gem_names, local_versions, remote_versions, outdated)
100
- gem_names.map do |name|
101
- remote = remote_versions[name]
102
- status = if outdated.include?(name) then 'available'
103
- elsif remote then 'current'
104
- else 'check_failed'
105
- end
106
- { name: name, from: local_versions[name], to: remote, status: status }
107
- end
108
- end
100
+ def fetch_outdated(gem_bin, gem_names)
101
+ output = `#{gem_bin} outdated 2>&1`
102
+ return {} unless $CHILD_STATUS.success?
109
103
 
110
- def current_results(gem_names, remote_versions)
111
- gem_names.map do |name|
112
- { name: name, status: remote_versions[name] ? 'current' : 'check_failed', remote: remote_versions[name] }
113
- end
104
+ parse_outdated(output, gem_names)
114
105
  end
115
106
 
116
- def install_results(gem_names, gem_bin, remote_versions, outdated)
117
- output = `#{gem_bin} install #{outdated.join(' ')} --no-document 2>&1`
118
- success = $CHILD_STATUS.success?
119
- gem_names.map do |name|
120
- if outdated.include?(name)
121
- { name: name, status: success ? 'installed' : 'failed', remote: remote_versions[name], output: output.strip }
122
- else
123
- { name: name, status: remote_versions[name] ? 'current' : 'check_failed', remote: remote_versions[name] }
124
- end
125
- end
126
- end
107
+ def parse_outdated(output, gem_names)
108
+ allowed = gem_names.to_set
109
+ output.each_line.with_object({}) do |line, map|
110
+ match = line.match(/^(\S+) \((\S+) < (\S+)\)/)
111
+ next unless match && allowed.include?(match[1])
127
112
 
128
- def fetch_remote_versions_parallel(gem_names)
129
- results = Concurrent::Hash.new
130
- thread_count = [gem_names.size, 4].min
131
- slices = gem_names.each_slice((gem_names.size / thread_count.to_f).ceil).to_a
132
- threads = slices.map do |batch|
133
- Thread.new(batch) do |names|
134
- fetch_batch(names, results)
135
- end
113
+ map[match[1]] = { local: match[2], remote: match[3] }
136
114
  end
137
- threads.each { |t| t.join(60) }
138
- results
139
115
  end
140
116
 
141
- def fetch_batch(names, results)
142
- Net::HTTP.start('rubygems.org', 443, use_ssl: true, open_timeout: 10, read_timeout: 10) do |http|
143
- names.each do |name|
144
- response = http.request(Net::HTTP::Get.new("/api/v1/versions/#{name}/latest.json"))
145
- next unless response.is_a?(Net::HTTPSuccess)
146
-
147
- data = ::JSON.parse(response.body)
148
- results[name] = data['version'] if data['version']
149
- rescue StandardError => e
150
- Legion::Logging.debug("UpdateCommand#fetch_batch #{name}: #{e.message}") if defined?(Legion::Logging)
151
- end
117
+ def install_outdated(gem_bin, pending, results)
118
+ names = pending.map { |r| r[:name] }
119
+ `#{gem_bin} install #{names.join(' ')} --no-document 2>&1`
120
+ success = $CHILD_STATUS.success?
121
+ pending_set = names.to_set
122
+ results.each do |r|
123
+ r[:status] = if pending_set.include?(r[:name])
124
+ success ? 'installed' : 'failed'
125
+ else
126
+ 'current'
127
+ end
152
128
  end
153
- rescue StandardError => e
154
- Legion::Logging.debug("UpdateCommand#fetch_batch connection: #{e.message}") if defined?(Legion::Logging)
129
+ results
155
130
  end
156
131
 
157
132
  def display_results(out, results, before, after)
158
133
  updated = []
159
134
  failed = []
160
- check_failures = 0
161
135
 
162
136
  results.each do |r|
163
137
  name = r[:name]
@@ -166,11 +140,7 @@ module Legion
166
140
  puts " #{name}: #{r[:from]} -> #{r[:to]}"
167
141
  updated << name
168
142
  when 'current'
169
- local = r[:from] || before[name]
170
- puts " #{name}: #{local || '?'} (already latest)"
171
- when 'check_failed'
172
- puts " #{name}: #{before[name]} (remote check failed)"
173
- check_failures += 1
143
+ puts " #{name}: #{r[:from] || before[name] || '?'} (already latest)"
174
144
  when 'installed'
175
145
  old_v = before[name]
176
146
  new_v = after[name]
@@ -190,8 +160,6 @@ module Legion
190
160
  out.spacer
191
161
  if updated.any?
192
162
  out.success("Updated #{updated.size} gem(s)")
193
- elsif check_failures.positive?
194
- puts "#{check_failures} gem(s) could not be checked - retry or use --dry-run for details"
195
163
  else
196
164
  puts 'All gems are up to date'
197
165
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Legion
4
- VERSION = '1.6.2'
4
+ VERSION = '1.6.3'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legionio
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.2
4
+ version: 1.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity