gel 0.3.0 → 0.8.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -3
  3. data/RELEASING.md +12 -0
  4. data/exe/gel +4 -2
  5. data/gemlib/gel/stub.rb +20 -0
  6. data/lib/gel/catalog/common.rb +4 -2
  7. data/lib/gel/catalog/compact_index.rb +6 -10
  8. data/lib/gel/catalog/dependency_index.rb +10 -10
  9. data/lib/gel/catalog/legacy_index.rb +4 -6
  10. data/lib/gel/catalog/marshal_hacks.rb +2 -0
  11. data/lib/gel/catalog.rb +33 -52
  12. data/lib/gel/catalog_set.rb +100 -0
  13. data/lib/gel/command/help.rb +13 -2
  14. data/lib/gel/command/lock.rb +3 -3
  15. data/lib/gel/command/open.rb +24 -0
  16. data/lib/gel/command/shell_setup.rb +11 -8
  17. data/lib/gel/command/stub.rb +45 -2
  18. data/lib/gel/command/version.rb +7 -0
  19. data/lib/gel/command.rb +43 -6
  20. data/lib/gel/compatibility/rubygems.rb +10 -197
  21. data/lib/gel/compatibility.rb +2 -2
  22. data/lib/gel/config.rb +41 -7
  23. data/lib/gel/db.rb +93 -83
  24. data/lib/gel/direct_gem.rb +16 -4
  25. data/lib/gel/environment.rb +542 -249
  26. data/lib/gel/error.rb +156 -24
  27. data/lib/gel/gemfile_parser.rb +74 -12
  28. data/lib/gel/gemspec_parser.rb +26 -7
  29. data/lib/gel/git_catalog.rb +15 -3
  30. data/lib/gel/git_depot.rb +62 -28
  31. data/lib/gel/httpool.rb +5 -2
  32. data/lib/gel/installer.rb +61 -23
  33. data/lib/gel/lock_loader.rb +87 -112
  34. data/lib/gel/lock_parser.rb +23 -31
  35. data/lib/gel/locked_store.rb +30 -21
  36. data/lib/gel/multi_store.rb +13 -4
  37. data/lib/gel/null_solver.rb +67 -0
  38. data/lib/gel/package/abortable.rb +18 -0
  39. data/lib/gel/package/installer.rb +124 -49
  40. data/lib/gel/package.rb +21 -4
  41. data/lib/gel/path_catalog.rb +1 -1
  42. data/lib/gel/pinboard.rb +4 -2
  43. data/lib/gel/platform.rb +38 -0
  44. data/lib/gel/pub_grub/package.rb +67 -0
  45. data/lib/gel/pub_grub/preference_strategy.rb +10 -6
  46. data/lib/gel/pub_grub/solver.rb +37 -0
  47. data/lib/gel/pub_grub/source.rb +64 -92
  48. data/lib/gel/resolved_gem_set.rb +234 -0
  49. data/lib/gel/runtime.rb +3 -3
  50. data/lib/gel/set.rb +62 -0
  51. data/lib/gel/stdlib.rb +83 -0
  52. data/lib/gel/store.rb +94 -25
  53. data/lib/gel/store_catalog.rb +2 -2
  54. data/lib/gel/store_gem.rb +54 -6
  55. data/lib/gel/stub_set.rb +32 -2
  56. data/lib/gel/support/cgi_escape.rb +34 -0
  57. data/lib/gel/support/gem_platform.rb +0 -2
  58. data/lib/gel/support/sha512.rb +142 -0
  59. data/lib/gel/support/tar/tar_writer.rb +2 -2
  60. data/lib/gel/tail_file.rb +2 -1
  61. data/lib/gel/util.rb +108 -0
  62. data/lib/gel/vendor/pstore.rb +3 -0
  63. data/lib/gel/vendor/pub_grub.rb +3 -0
  64. data/lib/gel/vendor/ruby_digest.rb +3 -0
  65. data/lib/gel/vendor_catalog.rb +38 -0
  66. data/lib/gel/version.rb +1 -1
  67. data/lib/gel.rb +15 -0
  68. data/man/man1/gel-exec.1 +1 -1
  69. data/man/man1/gel-install.1 +1 -1
  70. data/man/man1/gel.1 +14 -1
  71. data/{lib/gel/compatibility → slib}/bundler/cli.rb +0 -0
  72. data/{lib/gel/compatibility → slib}/bundler/friendly_errors.rb +0 -0
  73. data/{lib/gel/compatibility/rubygems/dependency_installer.rb → slib/bundler/gem_helper.rb} +0 -0
  74. data/slib/bundler/gem_tasks.rb +0 -0
  75. data/{lib/gel/compatibility → slib}/bundler/setup.rb +0 -0
  76. data/{lib/gel/compatibility → slib}/bundler.rb +39 -3
  77. data/{lib/gel/compatibility → slib}/rubygems/command.rb +0 -0
  78. data/slib/rubygems/dependency_installer.rb +12 -0
  79. data/{lib/gel/compatibility → slib}/rubygems/gem_runner.rb +0 -0
  80. data/slib/rubygems/package.rb +6 -0
  81. data/slib/rubygems/package_task.rb +7 -0
  82. data/slib/rubygems/specification.rb +0 -0
  83. data/slib/rubygems/version.rb +0 -0
  84. data/slib/rubygems.rb +297 -0
  85. data/vendor/pstore/LICENSE.txt +22 -0
  86. data/vendor/pstore/lib/pstore.rb +488 -0
  87. data/vendor/pub_grub/LICENSE.txt +21 -0
  88. data/vendor/pub_grub/lib/pub_grub/assignment.rb +20 -0
  89. data/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +183 -0
  90. data/vendor/pub_grub/lib/pub_grub/failure_writer.rb +182 -0
  91. data/vendor/pub_grub/lib/pub_grub/incompatibility.rb +143 -0
  92. data/vendor/pub_grub/lib/pub_grub/package.rb +35 -0
  93. data/vendor/pub_grub/lib/pub_grub/partial_solution.rb +121 -0
  94. data/vendor/pub_grub/lib/pub_grub/rubygems.rb +45 -0
  95. data/vendor/pub_grub/lib/pub_grub/solve_failure.rb +17 -0
  96. data/vendor/pub_grub/lib/pub_grub/static_package_source.rb +53 -0
  97. data/vendor/pub_grub/lib/pub_grub/term.rb +105 -0
  98. data/vendor/pub_grub/lib/pub_grub/version.rb +3 -0
  99. data/vendor/pub_grub/lib/pub_grub/version_constraint.rb +124 -0
  100. data/vendor/pub_grub/lib/pub_grub/version_range.rb +399 -0
  101. data/vendor/pub_grub/lib/pub_grub/version_solver.rb +247 -0
  102. data/vendor/pub_grub/lib/pub_grub/version_union.rb +174 -0
  103. data/vendor/pub_grub/lib/pub_grub.rb +31 -0
  104. data/vendor/ruby-digest/UNLICENSE +24 -0
  105. data/vendor/ruby-digest/lib/ruby_digest.rb +812 -0
  106. metadata +95 -19
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kernel
4
+ module_function
5
+
6
+ alias_method :abort_without_gel, :abort
7
+ singleton_class.undef_method :abort
8
+
9
+ def abort(message = nil)
10
+ IO.open(3, "w") { |f| f.write(message) }
11
+ abort_without_gel(message)
12
+ end
13
+ private :abort
14
+ end
15
+
16
+ class << Process
17
+ public :abort
18
+ end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fileutils"
4
- require "pathname"
5
3
  require "rbconfig"
6
4
  require "tempfile"
7
5
  require "shellwords"
8
6
 
7
+ require_relative "../util"
8
+
9
9
  class Gel::Package::Installer
10
10
  def initialize(store)
11
11
  @store = store
@@ -22,7 +22,7 @@ class Gel::Package::Installer
22
22
  g
23
23
  end
24
24
 
25
- class GemInstaller
25
+ class GemCompiler
26
26
  attr_reader :spec, :store, :root, :build_path
27
27
 
28
28
  def initialize(spec, store)
@@ -30,7 +30,13 @@ class Gel::Package::Installer
30
30
  @root_store = store
31
31
 
32
32
  if store.is_a?(Gel::MultiStore)
33
- store = store[spec.architecture, spec.extensions.any?]
33
+ platform_parts = []
34
+ platform_parts << spec.platform if spec.platform && spec.platform != "ruby"
35
+ platform_parts << spec.architecture if spec.architecture
36
+
37
+ platform_dir = platform_parts.join("-") unless platform_parts.empty?
38
+
39
+ store = store[platform_dir, spec.extensions.any?]
34
40
  end
35
41
  @store = store
36
42
 
@@ -39,25 +45,21 @@ class Gel::Package::Installer
39
45
  @config = Gel::Environment.config
40
46
 
41
47
  @root = store.gem_root(spec.name, spec.version)
42
- FileUtils.rm_rf(@root) if @root && Dir.exist?(@root)
48
+ Gel::Util.rm_rf(@root) if @root && Dir.exist?(@root)
43
49
 
44
50
  if spec.extensions.any?
45
51
  @build_path = store.extension_path(spec.name, spec.version)
46
- FileUtils.rm_rf(@build_path) if @build_path && Dir.exist?(@build_path)
52
+ Gel::Util.rm_rf(@build_path) if @build_path && Dir.exist?(@build_path)
47
53
  else
48
54
  @build_path = nil
49
55
  end
50
-
51
- @files = {}
52
- @installed_files = []
53
- spec.require_paths.each { |reqp| @files[reqp] = [] }
54
56
  end
55
57
 
56
58
  def abort!
57
- $stderr.puts "FileUtils.rm_rf(#{root.inspect})" if root
58
- $stderr.puts "FileUtils.rm_rf(#{build_path.inspect})" if build_path
59
- #FileUtils.rm_rf(root) if root
60
- #FileUtils.rm_rf(build_path) if build_path
59
+ $stderr.puts "Gel::Util.rm_rf(#{root.inspect})" if root
60
+ $stderr.puts "Gel::Util.rm_rf(#{build_path.inspect})" if build_path
61
+ #Gel::Util.rm_rf(root) if root
62
+ #Gel::Util.rm_rf(build_path) if build_path
61
63
  end
62
64
 
63
65
  def needs_compile?
@@ -71,8 +73,8 @@ class Gel::Package::Installer
71
73
  def with_build_environment(ext, install_dir)
72
74
  work_dir = File.expand_path(File.dirname(ext), root)
73
75
 
74
- FileUtils.mkdir_p(install_dir)
75
- short_install_dir = Pathname.new(install_dir).relative_path_from(Pathname.new(work_dir)).to_s
76
+ Gel::Util.mkdir_p(install_dir)
77
+ short_install_dir = Gel::Util.relative_path(work_dir, install_dir)
76
78
 
77
79
  local_config = Tempfile.new(["config", ".rb"])
78
80
  local_config.write(<<-RUBY)
@@ -114,7 +116,7 @@ class Gel::Package::Installer
114
116
  lockfile = Tempfile.new(["#{spec.name}.lockfile", ".lock"])
115
117
  lockfile.close
116
118
 
117
- Gel::Environment.lock(store: @root_store, output: nil, gemfile: Gel::GemfileParser.parse(File.read(gemfile.path), gemfile.path, 1), lockfile: lockfile.path)
119
+ Gel::Environment.write_lock(store: @root_store, output: nil, gemfile: Gel::GemfileParser.parse(File.read(gemfile.path), gemfile.path, 1), lockfile: lockfile.path)
118
120
 
119
121
  lockfile
120
122
  end
@@ -133,71 +135,93 @@ class Gel::Package::Installer
133
135
  }
134
136
  end
135
137
 
136
- def build_command(work_dir, log, *command, rake: false, **options)
138
+ def build_command(work_dir, log, *command, rake: false, abortable: false, **options)
137
139
  env = build_environment(rake: rake)
138
140
  env.merge!(command.shift) if command.first.is_a?(Hash)
139
141
 
142
+ options.update(chdir: work_dir, in: IO::NULL, [:out, :err] => log)
143
+
144
+ if abortable
145
+ abort_r, abort_w = IO.pipe
146
+ options.update(3 => abort_w)
147
+ end
148
+
140
149
  pid = spawn(
141
150
  env,
142
151
  *command,
143
- chdir: work_dir,
144
- in: IO::NULL,
145
- [:out, :err] => log,
146
- **options,
152
+ options,
147
153
  )
148
154
 
155
+ if abortable
156
+ abort_w.close
157
+
158
+ abort_message = abort_r.read
159
+ abort_message = nil if abort_message.strip.empty?
160
+ end
161
+
149
162
  _, status = Process.waitpid2(pid)
150
- status
163
+
164
+ if abortable
165
+ [status, abort_message]
166
+ else
167
+ status
168
+ end
151
169
  end
152
170
 
153
171
  def compile_extconf(ext, install_dir)
154
172
  with_build_environment(ext, install_dir) do |work_dir, short_install_dir, local_config_path, log|
155
- status = build_command(
173
+ status, abort = build_command(
156
174
  work_dir, log,
157
175
  { "MAKEFLAGS" => "-j3" },
158
176
  RbConfig.ruby,
177
+ "-r", File.expand_path("abortable", __dir__),
159
178
  "-r", local_config_path,
160
179
  File.basename(ext),
161
180
  *Shellwords.shellsplit(@config[:build, @spec.name] || ""),
181
+ abortable: true
162
182
  )
163
- raise "extconf exited with #{status.exitstatus}" unless status.success?
183
+ raise Gel::Error::ExtensionBuildError.new(program_name: "extconf", exitstatus: status.exitstatus, abort: abort, log: log.path) unless status.success?
164
184
 
165
185
  _status = build_command(work_dir, log, "make", "clean", "DESTDIR=")
166
186
  # Ignore exit status
167
187
 
168
188
  status = build_command(work_dir, log, "make", "-j3", "DESTDIR=")
169
- raise "make exited with #{status.exitstatus}" unless status.success?
189
+ raise Gel::Error::ExtensionBuildError.new(program_name: "make", exitstatus: status.exitstatus, log: log.path) unless status.success?
170
190
 
171
191
  status = build_command(work_dir, log, "make", "install", "DESTDIR=")
172
- raise "make install exited with #{status.exitstatus}" unless status.success?
192
+ raise Gel::Error::ExtensionBuildError.new(program_name: "make install", exitstatus: status.exitstatus, log: log.path) unless status.success?
173
193
  end
174
194
  end
175
195
 
176
196
  def compile_rakefile(ext, install_dir)
177
197
  with_build_environment(ext, install_dir) do |work_dir, short_install_dir, local_config_path, log|
178
198
  if File.basename(ext) =~ /mkrf_conf/i
179
- status = build_command(
199
+ status, abort = build_command(
180
200
  work_dir, log,
181
201
  RbConfig.ruby,
202
+ "-r", File.expand_path("abortable", __dir__),
182
203
  "-r", local_config_path,
183
204
  File.basename(ext),
184
205
  rake: true,
206
+ abortable: true
185
207
  )
186
- raise Gel::Error::ExtensionBuildError.new(program_name: "mkrf_conf", exitstatus: status.exitstatus) unless status.success?
208
+ raise Gel::Error::ExtensionBuildError.new(program_name: "mkrf_conf", exitstatus: status.exitstatus, abort: abort, log: log.path) unless status.success?
187
209
  end
188
210
 
189
- status = build_command(
211
+ status, abort = build_command(
190
212
  work_dir, log,
191
213
  { "RUBYARCHDIR" => short_install_dir, "RUBYLIBDIR" => short_install_dir },
192
214
  RbConfig.ruby,
215
+ "-r", File.expand_path("abortable", __dir__),
193
216
  "-r", File.expand_path("../command", __dir__),
194
217
  "-e", "Gel::Command.run(ARGV)",
195
218
  "--",
196
219
  "exec",
197
220
  "rake",
198
221
  rake: true,
222
+ abortable: true
199
223
  )
200
- raise Gel::Error::ExtensionBuildError.new(program_name: "rake", exitstatus: status.exitstatus) unless status.success?
224
+ raise Gel::Error::ExtensionBuildError.new(program_name: "rake", exitstatus: status.exitstatus, abort: abort, log: log.path) unless status.success?
201
225
  end
202
226
  end
203
227
 
@@ -215,29 +239,60 @@ class Gel::Package::Installer
215
239
  end
216
240
  end
217
241
  end
242
+ end
218
243
 
219
- def install
220
- loadable_file_types = ["rb", RbConfig::CONFIG["DLEXT"], RbConfig::CONFIG["DLEXT2"]].compact.reject(&:empty?)
221
- loadable_file_types_re = /\.#{Regexp.union loadable_file_types}\z/
222
- loadable_file_types_pattern = "*.{#{loadable_file_types.join(",")}}"
244
+ class GitCompiler < GemCompiler
245
+ def initialize(spec, store, path)
246
+ super(spec, store)
223
247
 
224
- store.add_gem(spec.name, spec.version, spec.bindir, spec.executables, spec.require_paths, spec.runtime_dependencies, spec.extensions.any?) do
225
- is_first = true
248
+ @root = @build_path = path
249
+ end
250
+ end
251
+
252
+ class GemInstaller < GemCompiler
253
+ def initialize(spec, store)
254
+ super
255
+
256
+ @files = {}
257
+ @installed_files = []
258
+ spec.require_paths&.each { |reqp| @files[reqp] = [] }
259
+ end
260
+
261
+ def install
262
+ store.add_gem(spec.name, spec.version, spec.bindir, spec.executables, spec.require_paths, spec.runtime_dependencies, spec.required_ruby_version, spec.extensions.any?) do
263
+ first_require_path = true
226
264
  spec.require_paths.each do |reqp|
227
- location = is_first ? spec.version : [spec.version, reqp]
228
- store.add_lib(spec.name, location, @files[reqp].map { |s| s.sub(loadable_file_types_re, "") })
229
- is_first = false
265
+ add_libs(spec, reqp, @files[reqp], first_subdir: first_require_path)
266
+ first_require_path = false
230
267
  end
231
268
 
232
269
  if build_path
233
- files = Dir["#{build_path}/**/#{loadable_file_types_pattern}"].map do |file|
234
- file[build_path.size + 1..-1]
235
- end.map do |file|
236
- file.sub(loadable_file_types_re, "")
270
+ files = Gel::Util.loadable_files(build_path)
271
+ add_libs(spec, Gel::StoreGem::EXTENSION_SUBDIR_TOKEN, files, first_subdir: false)
272
+ end
273
+ end
274
+ end
275
+
276
+ def add_libs(spec, subdir, files, first_subdir:)
277
+ hash = {}
278
+
279
+ files.each do |s|
280
+ basename, ext = Gel::Util.split_filename_for_require(s)
281
+ next if ext.nil?
282
+ (hash[ext] ||= []) << basename
283
+ end
284
+
285
+ hash.each do |ext, basenames|
286
+ location =
287
+ if ext != ".rb"
288
+ [spec.version, subdir, ext]
289
+ elsif !first_subdir
290
+ [spec.version, subdir]
291
+ else
292
+ spec.version
237
293
  end
238
294
 
239
- store.add_lib(spec.name, [spec.version, Gel::StoreGem::EXTENSION_SUBDIR_TOKEN], files)
240
- end
295
+ store.add_lib(spec.name, location, basenames)
241
296
  end
242
297
  end
243
298
 
@@ -246,21 +301,41 @@ class Gel::Package::Installer
246
301
  raise "invalid filename #{target.inspect} outside #{(root + "/").inspect}" unless target.start_with?("#{root}/")
247
302
  return if @installed_files.include?(target)
248
303
  @installed_files << target
304
+ requirable = false
249
305
  spec.require_paths.each do |reqp|
250
306
  prefix = "#{root}/#{reqp}/"
251
307
  if target.start_with?(prefix)
252
308
  @files[reqp] << target[prefix.size..-1]
309
+ requirable = true
253
310
  end
254
311
  end
255
- raise "won't overwrite #{target}" if File.exist?(target)
256
- FileUtils.mkdir_p(File.dirname(target))
312
+ exe = spec.executables.find { |e| filename == "#{spec.bindir}/#{e}" }
313
+
314
+ if File.exist?(target)
315
+ real = File.realpath(target)
316
+
317
+ if real && real.downcase == target.downcase && real != target && @installed_files.include?(real)
318
+ if requirable || exe
319
+ raise "Can't extract #{filename} because it conflicts with #{Gel::Util.relative_path(root, real)} (case-sensitive archive extracting on case-insensitive filesytem?)"
320
+ else
321
+ # Test or something? We'll skip it, and just hope it wasn't
322
+ # important.
323
+ return
324
+ end
325
+ end
326
+
327
+ raise "won't overwrite #{target}"
328
+ end
329
+
330
+ Gel::Util.mkdir_p(File.dirname(target))
257
331
  mode = 0444
258
332
  mode |= source_mode & 0200
259
333
  mode |= 0111 if source_mode & 0111 != 0
260
- if exe = spec.executables.find { |e| filename == "#{spec.bindir}/#{e}" }
334
+ if exe
261
335
  mode |= 0111
262
336
  @root_store.stub_set.add(File.basename(@store.root), [exe])
263
337
  end
338
+
264
339
  File.open(target, "wb", mode) do |f|
265
340
  f.write io.read
266
341
  end
data/lib/gel/package.rb CHANGED
@@ -3,7 +3,9 @@
3
3
  require "zlib"
4
4
  require "yaml"
5
5
 
6
+ require_relative "support/sha512"
6
7
  require_relative "support/tar"
8
+ require_relative "vendor/ruby_digest"
7
9
 
8
10
  module Gel
9
11
  class Package
@@ -24,6 +26,10 @@ module Gel
24
26
  @inner.architecture
25
27
  end
26
28
 
29
+ def platform
30
+ @inner.platform
31
+ end
32
+
27
33
  def bindir
28
34
  @inner.bindir
29
35
  end
@@ -40,6 +46,10 @@ module Gel
40
46
  @inner.extensions
41
47
  end
42
48
 
49
+ def required_ruby_version
50
+ @inner.required_ruby_version&.requirements&.map { |pair| pair.map(&:to_s) }
51
+ end
52
+
43
53
  def runtime_dependencies
44
54
  h = {}
45
55
  @inner.dependencies.each do |dep|
@@ -70,7 +80,7 @@ module Gel
70
80
  end
71
81
 
72
82
  def initialize
73
- super(%w(Symbol Time), [])
83
+ super(%w(Symbol Time Date), [])
74
84
  end
75
85
 
76
86
  def find(klass)
@@ -91,7 +101,7 @@ module Gel
91
101
  end
92
102
 
93
103
  class Gem_Specification
94
- attr_accessor :architecture, :bindir, :executables, :name, :require_paths, :specification_version, :version, :dependencies, :extensions
104
+ attr_accessor :architecture, :bindir, :executables, :name, :platform, :require_paths, :specification_version, :version, :dependencies, :extensions, :required_ruby_version
95
105
  end
96
106
  class Gem_Dependency
97
107
  attr_accessor :name, :requirement, :type, :version_requirements
@@ -110,8 +120,15 @@ module Gel
110
120
  stream.rewind
111
121
 
112
122
  checksums.each do |type, map|
113
- next unless %w(SHA1 SHA512).include?(type)
114
- calculated = Digest(type).hexdigest(data)
123
+ calculated =
124
+ case type
125
+ when "SHA1"
126
+ Gel::Vendor::RubyDigest::SHA1.hexdigest(data)
127
+ when "SHA512"
128
+ Gel::Support::SHA512.hexdigest(data)
129
+ else
130
+ next
131
+ end
115
132
  raise "#{type} checksum mismatch on #{filename}" unless calculated == map[filename]
116
133
  end
117
134
  end
@@ -27,7 +27,7 @@ class Gel::PathCatalog
27
27
  gemspec = gemspec_from(gemspec)
28
28
 
29
29
  info = {}
30
- info[gemspec.version] = {
30
+ info[Gel::Support::GemVersion.new(gemspec.version).to_s] = {
31
31
  dependencies: gemspec.runtime_dependencies,
32
32
  ruby: gemspec.required_ruby_version,
33
33
  }
data/lib/gel/pinboard.rb CHANGED
@@ -4,6 +4,7 @@ require_relative "db"
4
4
  require_relative "httpool"
5
5
  require_relative "tail_file"
6
6
  require_relative "work_pool"
7
+ require_relative "vendor/ruby_digest"
7
8
 
8
9
  # For each URI, this stores:
9
10
  # * the current etag
@@ -117,7 +118,8 @@ class Gel::Pinboard
117
118
  def updated(uri, etag, changed = true)
118
119
  blocks = nil
119
120
  @monitor.synchronize do
120
- @db[uri.to_s] = read(uri).merge(etag: etag, stale: false)
121
+ h = read(uri) || {}
122
+ @db[uri.to_s] = h.merge(etag: etag, stale: false)
121
123
 
122
124
  blocks = @waiting.delete(uri)
123
125
  end
@@ -135,6 +137,6 @@ class Gel::Pinboard
135
137
  private
136
138
 
137
139
  def mangle_uri(uri)
138
- "#{uri.hostname}--#{uri.path.gsub(/[^A-Za-z0-9]+/, "-")}--#{Digest(:SHA256).hexdigest(uri.to_s)[0, 12]}"
140
+ "#{uri.hostname}--#{uri.path.gsub(/[^A-Za-z0-9]+/, "-")}--#{Gel::Vendor::RubyDigest::SHA256.hexdigest(uri.to_s)[0, 12]}"
139
141
  end
140
142
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gel::Platform
4
+ SYNONYMS = [
5
+ ["ruby", "mri", "rbx"],
6
+ ["java", "jruby"],
7
+ ["x64-mingw32", "mswin64", "x64_mingw"],
8
+ ["x86-mingw32", "mswin", "mingw"],
9
+ ]
10
+
11
+ def self.filter(target_platforms, filter)
12
+ # Ignore ruby-version constraint tails ("mri_23" => "mri")
13
+ filter = filter.map { |f| f.sub(/_[0-9]+\z/, "") }
14
+
15
+ target_platforms.select do |platform|
16
+ next true if filter.include?(platform)
17
+
18
+ SYNONYMS.any? do |row|
19
+ row.include?(platform) && !(row & filter).empty?
20
+ end
21
+ end
22
+ end
23
+
24
+ def self.match(target_platform, available_platforms)
25
+ return target_platform if available_platforms.include?(target_platform)
26
+
27
+ SYNONYMS.each do |row|
28
+ next unless row.include?(target_platform)
29
+
30
+ overlap = row & available_platforms
31
+ return overlap.first unless overlap.empty?
32
+ end
33
+
34
+ return "ruby" if available_platforms.include?("ruby")
35
+
36
+ nil
37
+ end
38
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gel::PubGrub
4
+ ##
5
+ # Based on PubGrub::Package, but we need some extra tricks
6
+ class Package
7
+ attr_reader :name
8
+ attr_reader :platform
9
+
10
+ def initialize(name, platform)
11
+ @name = name
12
+ @platform = platform
13
+ end
14
+
15
+ def inspect
16
+ "#<#{self.class} #{name.inspect} (#{platform})>"
17
+ end
18
+
19
+ def <=>(other)
20
+ return 1 if other.is_a?(Pseudo)
21
+ (name <=> other.name).nonzero? || (platform <=> other.platform)
22
+ end
23
+
24
+ def to_s
25
+ "#{name} (#{platform})"
26
+ end
27
+
28
+ def hash
29
+ name.hash ^ platform.hash
30
+ end
31
+
32
+ def eql?(other)
33
+ self.class.eql?(other.class) && name.eql?(other.name) && platform.eql?(other.platform)
34
+ end
35
+ alias == eql?
36
+
37
+ class Pseudo
38
+ attr_reader :role
39
+
40
+ def initialize(role)
41
+ @role = role
42
+ end
43
+
44
+ def inspect
45
+ "#<#{self.class} #{role}>"
46
+ end
47
+
48
+ def <=>(other)
49
+ return -1 unless other.is_a?(Pseudo)
50
+ role <=> other.role
51
+ end
52
+
53
+ def to_s
54
+ "[[#{role}]]"
55
+ end
56
+
57
+ def hash
58
+ role.hash
59
+ end
60
+
61
+ def eql?(other)
62
+ self.class.eql?(other.class) && role.eql?(other.role)
63
+ end
64
+ alias == eql?
65
+ end
66
+ end
67
+ end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Gel::PubGrub
4
4
  class PreferenceStrategy
5
- def initialize(loader, overrides, bump: :major, strict: false)
6
- @loader = loader
5
+ def initialize(gem_set, overrides, bump: :major, strict: false)
6
+ @gem_set = gem_set
7
7
  @overrides = overrides
8
8
  @bump = bump
9
9
  @strict = strict
@@ -12,7 +12,7 @@ module Gel::PubGrub
12
12
  # Overrides first, then packages for which we have a preference (and
13
13
  # that preference is still in play), then everything else.
14
14
  def package_priority(package, versions)
15
- if package.name =~ /^~/
15
+ if package.is_a?(Package::Pseudo)
16
16
  -1000
17
17
  elsif @overrides.key?(package.name)
18
18
  -100
@@ -34,8 +34,12 @@ module Gel::PubGrub
34
34
  versions.partition { |version| range.satisfied_by?(version) }.inject(:+)
35
35
  end
36
36
 
37
+ def refresh_git?(name)
38
+ @overrides.key?(name) || @bump != :hold
39
+ end
40
+
37
41
  def constraints
38
- ranges = @strict ? self.ranges : @overrides
42
+ ranges = @strict ? ranges() : @overrides
39
43
 
40
44
  result = {}
41
45
  ranges.each do |package_name, range|
@@ -50,10 +54,10 @@ module Gel::PubGrub
50
54
  @ranges ||=
51
55
  begin
52
56
  result = @overrides.dup
53
- @loader.each_gem do |section, body, name, version, platform, deps|
57
+ @gem_set.gems.each do |name, resolved_gems|
54
58
  next if @overrides.key?(name)
55
59
 
56
- result[name] = range_for(version, @bump)
60
+ result[name] = range_for(resolved_gems.first.version, @bump)
57
61
  end
58
62
  result.delete_if { |_, v| !v }
59
63
  result
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "source"
4
+
5
+ class Gel::PubGrub::Solver < Gel::Vendor::PubGrub::VersionSolver
6
+ def self.logger
7
+ ::Gel::Vendor::PubGrub.logger
8
+ end
9
+
10
+ def initialize(gemfile:, catalog_set:, platforms:, strategy:)
11
+ source = Gel::PubGrub::Source.new(gemfile, catalog_set, platforms, strategy)
12
+
13
+ super(source: source, root: source.root)
14
+
15
+ @strategy = strategy
16
+ end
17
+
18
+ def next_package_to_try
19
+ self.solution.unsatisfied.min_by do |term|
20
+ package = term.package
21
+ versions = self.source.versions_for(package, term.constraint.range)
22
+
23
+ if @strategy
24
+ @strategy.package_priority(package, versions) + @package_depth[package]
25
+ else
26
+ @package_depth[package]
27
+ end * 1000 + versions.count
28
+ end.package
29
+ end
30
+
31
+ def each_resolved_package(&block)
32
+ result.each do |package, version|
33
+ next if package.is_a?(Gel::PubGrub::Package::Pseudo)
34
+ yield package, version
35
+ end
36
+ end
37
+ end