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
data/lib/gel/command.rb CHANGED
@@ -8,16 +8,25 @@ class Gel::Command
8
8
  command_line = command_line.dup
9
9
  if command_name = extract_word(command_line)
10
10
  const = command_name.downcase.sub(/^./, &:upcase).gsub(/[-_]./) { |s| s[1].upcase }
11
- if Gel::Command.const_defined?(const, false)
12
- command = Gel::Command.const_get(const, false).new
13
- command.run(command_line)
14
- elsif Gel::Environment.activate_for_executable(["gel-#{command_name}", command_name])
15
- command_name = "gel-#{command_name}" if Gel::Environment.find_executable("gel-#{command_name}")
11
+ if const =~ /\A[a-z]+\z/i
12
+ if Gel::Command.const_defined?(const, false)
13
+ command = Gel::Command.const_get(const, false).new
14
+ command.run(command_line)
15
+ elsif Gel::Environment.activate_for_executable(["gel-#{command_name}", command_name])
16
+ command_name = "gel-#{command_name}" if Gel::Environment.find_executable("gel-#{command_name}")
17
+ command = Gel::Command::Exec.new
18
+ command.run([command_name, *command_line])
19
+ else
20
+ raise Gel::Error::UnknownCommandError.new(command_name: command_name)
21
+ end
22
+ elsif stub_name = own_stub_file?(command_name) || other_stub_file?(command_name)
16
23
  command = Gel::Command::Exec.new
17
- command.run([command_name, *command_line])
24
+ command.run([stub_name, *command_line], from_stub: true)
18
25
  else
19
26
  raise Gel::Error::UnknownCommandError.new(command_name: command_name)
20
27
  end
28
+ elsif flag_constant = flags(command_line).first
29
+ flag_constant.new.run(command_line)
21
30
  else
22
31
  puts <<~EOF
23
32
  Gel doesn't have a default command; please run `gel install`
@@ -68,12 +77,39 @@ class Gel::Command
68
77
  end
69
78
  end
70
79
 
80
+ def self.own_stub_file?(path)
81
+ # If it's our own stub file, we can skip reading and parsing it, and
82
+ # just trust that the basename is correct.
83
+ if Gel::Environment.store.stub_set.own_stub?(path)
84
+ File.basename(path)
85
+ end
86
+ end
87
+
88
+ def self.other_stub_file?(path)
89
+ Gel::Environment.store.stub_set.parse_stub(path)
90
+ end
91
+
92
+ def self.flags(arguments)
93
+ flag_constants = {
94
+ "h" => Gel::Command::Help,
95
+ "help" => Gel::Command::Help,
96
+ "v" => Gel::Command::Version,
97
+ "version" => Gel::Command::Version,
98
+ }
99
+
100
+ arguments.map { |word|
101
+ match = word.match(/-+(?<flag>\w+)/)
102
+ match && flag_constants[match[:flag]]
103
+ }.compact
104
+ end
105
+
71
106
  # If set to true, an error raised from #run will pass straight up to
72
107
  # ruby instead of being treated as an internal Gel error
73
108
  attr_accessor :reraise
74
109
  end
75
110
 
76
111
  require_relative "command/help"
112
+ require_relative "command/version"
77
113
  require_relative "command/install"
78
114
  require_relative "command/install_gem"
79
115
  require_relative "command/env"
@@ -84,3 +120,4 @@ require_relative "command/ruby"
84
120
  require_relative "command/stub"
85
121
  require_relative "command/config"
86
122
  require_relative "command/shell_setup"
123
+ require_relative "command/open"
@@ -1,201 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # The goal here is not to be a full drop-in replacement of RubyGems'
4
- # API.
3
+ # Deprecation plan: Ship this without a warning for at least one
4
+ # version, so people with an existing `gel shell-setup`-configured shell
5
+ # don't get messages immediately after updating.
5
6
  #
6
- # The threshold is basically "things that already-popular/established
7
- # gems assume are there without checking".
8
-
9
- require_relative "../runtime"
10
-
11
- module Gem
12
- Version = Gel::Support::GemVersion
13
- Requirement = Gel::Support::GemRequirement
14
-
15
- class Dependency
16
- attr_reader :name
17
- attr_reader :requirement
18
- attr_reader :type
19
-
20
- def initialize(name, requirement, type)
21
- @name = name
22
- @requirement = requirement
23
- @type = type
24
- end
25
- end
26
-
27
- LoadError = Class.new(::LoadError)
28
-
29
- class Specification
30
- def self.find_by_name(name, *requirements)
31
- if g = Gel::Environment.find_gem(name, *requirements)
32
- new(g)
33
- else
34
- # TODO: Should probably be a Gel exception instead?
35
- raise Gem::LoadError, "Unable to find gem #{name.inspect}" + (requirements.empty? ? "" : " (#{requirements.join(", ")})")
36
- end
37
- end
38
-
39
- def self.each(&block)
40
- Gel::Environment.store.each.map { |g| new(g) }.each(&block)
41
- end
42
-
43
- def initialize(store_gem)
44
- @store_gem = store_gem
45
- end
46
-
47
- def name
48
- @store_gem.name
49
- end
50
-
51
- def version
52
- Gem::Version.new(@store_gem.version)
53
- end
54
-
55
- def dependencies
56
- @store_gem.dependencies.map do |name, pairs|
57
- Gem::Dependency.new(name, pairs.map { |op, ver| "#{op} #{ver}" }, :runtime)
58
- end
59
- end
60
- alias runtime_dependencies dependencies
61
-
62
- def gem_dir
63
- @store_gem.root
64
- end
65
- alias full_gem_path gem_dir
66
-
67
- def require_paths
68
- base = Pathname.new(gem_dir)
69
-
70
- @store_gem.require_paths.map do |path|
71
- Pathname.new(path).relative_path_from(base).to_s
72
- end
73
- end
74
- end
75
-
76
- class DependencyInstaller
77
- def install(name, requirement = nil)
78
- require_relative "../catalog"
79
- require_relative "../work_pool"
80
-
81
- Gel::WorkPool.new(2) do |work_pool|
82
- catalog = Gel::Catalog.new("https://rubygems.org", work_pool: work_pool)
83
-
84
- return Gel::Environment.install_gem([catalog], name, requirement)
85
- end
86
- end
87
- end
88
-
89
- def self.try_activate(file)
90
- Gel::Environment.resolve_gem_path(file) != file
91
- rescue LoadError
92
- false
93
- end
94
-
95
- def self.ruby
96
- RbConfig.ruby
97
- end
98
-
99
- def self.win_platform?
100
- false
101
- end
102
-
103
- def self.loaded_specs
104
- result = {}
105
- Gel::Environment.activated_gems.each do |name, store_gem|
106
- result[name] = Gem::Specification.new(store_gem)
107
- end
108
- result
109
- end
110
-
111
- def self.find_files(pattern)
112
- Gel::Environment.store.each.
113
- flat_map(&:require_paths).
114
- flat_map { |dir| Dir[File.join(dir, pattern)] }
115
- end
116
-
117
- def self.refresh
118
- # no-op
119
- end
120
-
121
- def self.path
122
- Gel::Environment.store.paths
123
- end
124
-
125
- def self.default_dir
126
- path.first
127
- end
128
-
129
- def self.activate_bin_path(gem_name, bin_name, version = nil)
130
- if gem_name == "bundler" && bin_name == "bundle"
131
- # Extra-special case: this is the bundler binstub, we need to
132
- # re-exec to hand over.
133
-
134
- ENV["RUBYLIB"] = Gel::Environment.original_rubylib
135
- exec RbConfig.ruby, "--", $0, *ARGV
136
- end
137
-
138
- if gem_name == "gel" && bin_name == "gel"
139
- # Another extra-special case: gel is already activated, but it's
140
- # being invoked via a rubygems-installed binstub. We can't
141
- # activate gel inside gel, but we also don't need to: we know
142
- # exactly which file they need.
143
-
144
- return File.expand_path("../../../exe/gel", __dir__)
145
- end
146
-
147
- if g = Gel::Environment.activated_gems[gem_name]
148
- Gel::Environment.gem g.name, version if version
149
- elsif g = Gel::Environment.find_gem(gem_name, *version) do |g|
150
- g.executables.include?(bin_name)
151
- end
152
-
153
- Gel::Environment.gem g.name, g.version
154
- elsif g = Gel::Environment.find_gem(gem_name, *version)
155
- raise "#{g.name} (#{g.version}) doesn't contain executable #{bin_name.inspect}"
156
- elsif version && Gel::Environment.find_gem(gem_name)
157
- raise "#{gem_name} (#{version}) not available"
158
- else
159
- raise "Unknown gem #{gem_name.inspect}"
160
- end
161
-
162
- Gel::Environment.find_executable(bin_name, g.name, g.version)
163
- rescue => ex
164
- # This method may be our entry-point, if we're being invoked by a
165
- # rubygems binstub. Detect that situation, and provide nicer error
166
- # reporting.
167
-
168
- raise unless locations = caller_locations(2, 2)
169
- raise unless locations.size == 1
170
- raise unless path = locations.first.absolute_path
171
- raise unless File.exist?(path) && File.readable?(path)
172
- raise unless File.open(path, "rb") { |f| f.read(1024).include?("\n# This file was generated by RubyGems.\n") }
173
-
174
- require_relative "../command"
175
- Gel::Command.handle_error(ex)
176
- end
177
-
178
- def self.bin_path(gem_name, bin_name, version = nil)
179
- if g = Gel::Environment.activated_gems[gem_name]
180
- Gel::Environment.gem g.name, version if version
181
-
182
- Gel::Environment.find_executable(bin_name, g.name, g.version)
183
- elsif Gel::Environment.find_gem(gem_name)
184
- raise "Gem #{gem_name.inspect} is not active"
185
- else
186
- raise "Unknown gem #{gem_name.inspect}"
187
- end
188
- end
189
- end
190
-
191
- def gem(*args)
192
- Gel::Environment.gem(*args)
193
- end
194
- private :gem
195
-
196
- def require(path)
197
- super Gel::Environment.resolve_gem_path(path)
198
- end
199
- private :require
7
+ # After that, we'll ship the below message for at least one version,
8
+ # catching anyone whose terminal session is still alive from before the
9
+ # above, as well as anyone setting RUBYLIB manually.
10
+ #
11
+ # Finally, we can remove this file and surrounding directory entirely.
200
12
 
201
- require "rubygems/deprecate"
13
+ #$stderr.puts "Gel: lib/gel/compatibility/ is deprecated; please update your RUBYLIB to point to slib/, or use `gel shell-setup`. Restarting your shell may resolve this warning."
14
+ require_relative "../compatibility"
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- $:[0, 0] = File.expand_path("compatibility", __dir__)
4
- require_relative "compatibility/rubygems"
3
+ $:[0, 0] = File.expand_path("../../slib", __dir__)
4
+ require_relative "../../slib/rubygems"
data/lib/gel/config.rb CHANGED
@@ -1,8 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "util"
4
+
5
+ ##
6
+ # Reads an optional config file ~/.config/gel/config and injects
7
+ # authorization info from the environment $GEL_AUTH.
8
+ #
9
+ # Environment format:
10
+ #
11
+ # GEL_AUTH="https://user@pass:host1/ https://user@pass:host2/"
12
+ #
13
+ # Config file format:
14
+ #
15
+ # # comment:
16
+ # context-name: # where context-name in [build]
17
+ # key: val
18
+ #
19
+ # key: val
20
+ #
21
+ # Example:
22
+ #
23
+ # build:
24
+ # nokogiri: --libdir=blah
25
+ #
26
+ # rails-assets.org: username:password
27
+ #
28
+ # ---
29
+ #
30
+ # GEL_AUTH="https://user@pass:private-gem-server.local"
31
+
3
32
  class Gel::Config
4
- def initialize
5
- @root = File.expand_path("~/.config/gel")
33
+ def initialize(root_path = "~/.config/gel")
34
+ @root = File.expand_path(root_path)
6
35
  @path = File.join(@root, "config")
7
36
  @config = nil
8
37
  end
@@ -12,10 +41,6 @@ class Gel::Config
12
41
  end
13
42
 
14
43
  def [](group = nil, key)
15
- if group.nil?
16
- group, key = key.split(".", 2)
17
- end
18
-
19
44
  (group ? (config[group.to_s] || {}) : config)[key.to_s]
20
45
  end
21
46
 
@@ -50,11 +75,20 @@ class Gel::Config
50
75
  end
51
76
  end
52
77
  end
78
+
79
+ # GEL_AUTH = "http://username:password@host http://username:password@host"
80
+ if auths = ENV["GEL_AUTH"] then
81
+ auths.split.each do |auth|
82
+ auth = URI(auth)
83
+ result[auth.host] = auth.userinfo
84
+ end
85
+ end
86
+
53
87
  result
54
88
  end
55
89
 
56
90
  def write(data)
57
- Dir.mkdir(@root) unless Dir.exist?(@root)
91
+ Gel::Util.mkdir_p(@root)
58
92
 
59
93
  tempfile = File.join(@root, ".config.#{Process.pid}")
60
94
  File.open(tempfile, "w", 0644) do |f|
data/lib/gel/db.rb CHANGED
@@ -1,11 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- begin
4
- require "sdbm"
5
- rescue LoadError
6
- end
7
- require "pstore"
8
- require "pathname"
3
+ require_relative "util"
4
+ require_relative "vendor/pstore"
9
5
 
10
6
  require "monitor"
11
7
 
@@ -13,11 +9,7 @@ class Gel::DB
13
9
  def self.new(root, name)
14
10
  return super unless self == Gel::DB
15
11
 
16
- if defined? ::SDBM
17
- SDBM.new(root, name)
18
- else
19
- PStore.new(root, name)
20
- end
12
+ PStore.new(root, name)
21
13
  end
22
14
 
23
15
  def initialize(root, name)
@@ -40,6 +32,9 @@ class Gel::DB
40
32
 
41
33
  def []=(key, value)
42
34
  end
35
+
36
+ def delete(key)
37
+ end
43
38
  end
44
39
 
45
40
  module Gel::DB::AutoTransaction
@@ -133,6 +128,14 @@ module Gel::DB::AutoTransaction
133
128
  end
134
129
  end
135
130
 
131
+ def delete(key)
132
+ if write?
133
+ super
134
+ else
135
+ writing { super }
136
+ end
137
+ end
138
+
136
139
  private
137
140
 
138
141
  def marshal_dump
@@ -144,121 +147,112 @@ module Gel::DB::AutoTransaction
144
147
  end
145
148
  end
146
149
 
147
- class Gel::DB::SDBM < Gel::DB
148
- prepend Gel::DB::AutoTransaction
149
- SDBM_MAX_STORE_SIZE = 1000 - 1 # arbitrary on PBLKSIZ-N
150
- SAFE_DELIMITER = '---'
151
-
152
- def initialize(root, name)
153
- @sdbm = ::SDBM.new("#{root}/#{name}")
150
+ module Gel::DB::Cache
151
+ def initialize(*)
152
+ @cache = nil
153
+ super
154
154
  end
155
155
 
156
- def writing
157
- yield
156
+ def writing(&block)
157
+ @cache = nil
158
+ super
158
159
  end
159
160
 
160
- def reading
161
+ def reading(&block)
162
+ if @cache.nil?
163
+ super do
164
+ cache = {}
165
+ each_key do |k|
166
+ cache[k] = self[k]
167
+ end
168
+ @cache = cache
169
+ end
170
+ end
171
+
161
172
  yield
162
173
  end
163
174
 
164
175
  def each_key(&block)
165
- @sdbm.each_key(&block)
176
+ if @cache
177
+ @cache.each_key(&block)
178
+ else
179
+ super
180
+ end
166
181
  end
167
182
 
168
183
  def key?(key)
169
- !!@sdbm[key.to_s]
170
- end
171
-
172
- ##
173
- # Retrieve the value from SDBM and handle for when we split
174
- # over multiple stores. It is safe to assume that the value
175
- # stored will be a marshaled value or a integer implying the
176
- # amount of extra stores to retrieve the data string form. A
177
- # marshaled store would have special starting delimiter that
178
- # is not a decimal. If a number is not found at start of string
179
- # then simply load it as a string and you get a value that
180
- # is then marshaled.
181
- def [](key)
182
- value = @sdbm[key.to_s]
183
- return nil unless value
184
-
185
- if value =~ /\A~(\d+)\z/
186
- value = $1.to_i.times.map do |idx|
187
- @sdbm["#{key}#{SAFE_DELIMITER}#{idx}"]
188
- end.join
184
+ if @cache
185
+ @cache.key?(key)
186
+ else
187
+ super
189
188
  end
190
-
191
- return Marshal.load(value)
192
189
  end
193
190
 
194
-
195
- ##
196
- # SDBM has an arbitrary limit on the size of a string it stores,
197
- # so we simply split any string over multiple stores for the edge
198
- # case when it reaches this. It's optimised to take advantage of the common
199
- # case where this is not needed.
200
- # When the edge case is hit, the first value in the storage will be the amount
201
- # of extra values stored to hold the split string. This amount is determined by string
202
- # size split by the arbitrary limit imposed by SDBM
203
- def []=(key, value)
204
- return unless value && key
205
-
206
- dump = Marshal.dump(value)
207
- count = dump.length / SDBM_MAX_STORE_SIZE
208
-
209
- if count > 0
210
- count += 1
211
- @sdbm["#{key.to_s}"] = "~#{count}"
212
- count.times.map do |idx|
213
- @sdbm["#{key.to_s}#{SAFE_DELIMITER}#{idx}"] = dump.slice!(0, SDBM_MAX_STORE_SIZE)
214
- end
191
+ def [](key)
192
+ if @cache
193
+ @cache[key]
215
194
  else
216
- @sdbm[key.to_s] = dump
195
+ super
217
196
  end
218
197
  end
219
198
  end
220
199
 
221
200
  class Gel::DB::PStore < Gel::DB
201
+ prepend Gel::DB::Cache
222
202
  prepend Gel::DB::AutoTransaction
223
203
 
224
204
  def initialize(root, name)
225
- @pstore = ::PStore.new("#{root}/#{name}.pstore", true)
205
+ @filename = "#{root}/#{name}.pstore"
206
+ @pstore = (store if ::File.exist?(@filename))
226
207
  end
227
208
 
228
209
  def writing(&block)
210
+ @pstore ||= store
229
211
  @pstore.transaction(false, &block)
230
212
  end
231
213
 
232
214
  def reading(&block)
233
- @pstore.transaction(true, &block)
215
+ @pstore = store if @pstore.nil? && ::File.exist?(@filename)
216
+ @pstore&.transaction(true, &block)
234
217
  end
235
218
 
236
219
  def each_key(&block)
237
- @pstore.roots.each(&block)
220
+ @pstore.roots.each(&block) if @pstore
238
221
  end
239
222
 
240
223
  def key?(key)
241
- @pstore.key?(key.to_s)
224
+ @pstore&.root?(key.to_s)
242
225
  end
243
226
 
244
227
  def [](key)
245
- @pstore[key.to_s]
228
+ @pstore && @pstore[key.to_s]
246
229
  end
247
230
 
248
231
  def []=(key, value)
249
232
  @pstore[key.to_s] = value
250
233
  end
234
+
235
+ def delete(key)
236
+ @pstore.delete(key.to_s)
237
+ end
238
+
239
+ private
240
+
241
+ def store
242
+ Gel::Util.mkdir_p(::File.dirname(@filename))
243
+ Gel::Vendor::PStore.new(@filename, true)
244
+ end
251
245
  end
252
246
 
253
247
  class Gel::DB::File < Gel::DB
254
248
  prepend Gel::DB::AutoTransaction
255
249
 
256
250
  def initialize(root, name)
257
- @path = Pathname.new("#{root}/#{name}")
251
+ @base = "#{root}/#{name}"
258
252
  end
259
253
 
260
254
  def writing
261
- @path.mkdir unless @path.exist?
255
+ Gel::Util.mkdir_p(@base)
262
256
  yield
263
257
  end
264
258
 
@@ -267,28 +261,44 @@ class Gel::DB::File < Gel::DB
267
261
  end
268
262
 
269
263
  def each_key
270
- @path.each_child(false) do |child|
271
- yield child.to_s
264
+ return unless Dir.exist?(@base)
265
+ Dir.each_child(@base) do |child|
266
+ yield child
272
267
  end
273
268
  end
274
269
 
275
270
  def key?(key)
276
- @path.join(key).exist?
271
+ ::File.exist?(path(key))
277
272
  end
278
273
 
279
274
  def [](key)
280
- child = @path.join(key)
281
- if child.exist?
282
- Marshal.load(child.binread)
275
+ child = path(key)
276
+ if ::File.exist?(child)
277
+ Marshal.load(IO.binread(child))
283
278
  end
284
279
  end
285
280
 
286
281
  def []=(key, value)
287
- child = @path.join(key)
282
+ child = path(key)
288
283
  if value
289
- child.binwrite Marshal.dump(value)
290
- elsif child.exist?
291
- child.unlink
284
+ IO.binwrite child, Marshal.dump(value)
285
+ elsif ::File.exist?(child)
286
+ ::File.unlink(child)
292
287
  end
293
288
  end
289
+
290
+ def delete(key)
291
+ child = path(key)
292
+ if ::File.exist?(child)
293
+ value = Marshal.load(IO.binread(child))
294
+ ::File.unlink(child)
295
+ value
296
+ end
297
+ end
298
+
299
+ private
300
+
301
+ def path(key)
302
+ ::Gel::Util.join(@base, key)
303
+ end
294
304
  end
@@ -5,9 +5,19 @@ class Gel::DirectGem < Gel::StoreGem
5
5
  Gel::GemspecParser.parse(File.read(filename), filename, isolate: false)
6
6
  end
7
7
 
8
- def initialize(root, name, version = nil)
8
+ def self.from_block(*args, &block)
9
+ filename, _lineno = block.source_location
10
+
11
+ result = Gel::GemspecParser::Context::Gem::Specification.new(*args, &block)
12
+
13
+ new(File.dirname(filename), result.name, loaded_gemspec: result)
14
+ end
15
+
16
+ def initialize(root, name, version = nil, loaded_gemspec: nil)
9
17
  root = File.expand_path(root)
10
- if File.exist?("#{root}/#{name}.gemspec")
18
+ if loaded_gemspec
19
+ gemspec = loaded_gemspec
20
+ elsif File.exist?("#{root}/#{name}.gemspec")
11
21
  gemspec = load_gemspec("#{root}/#{name}.gemspec")
12
22
  elsif File.exist?("#{root}/#{name}/#{name}.gemspec")
13
23
  root = "#{root}/#{name}"
@@ -17,13 +27,15 @@ class Gel::DirectGem < Gel::StoreGem
17
27
  return
18
28
  end
19
29
 
30
+ require_paths = gemspec.require_paths&.compact || [gemspec.require_path || "lib"]
31
+
20
32
  info = {
21
33
  bindir: gemspec.bindir || "bin",
22
34
  executables: gemspec.executables,
23
- require_paths: gemspec.require_paths || [gemspec.require_path].compact,
35
+ require_paths: require_paths,
24
36
  dependencies: gemspec.runtime_dependencies,
25
37
  }
26
38
 
27
- super(root, name, version || gemspec.version, gemspec.extensions, info)
39
+ super(root, name, version || Gel::Support::GemVersion.new(gemspec.version).to_s, ("#{root}/ext" if gemspec.extensions.any?), info)
28
40
  end
29
41
  end