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.
- checksums.yaml +4 -4
- data/README.md +26 -3
- data/RELEASING.md +12 -0
- data/exe/gel +4 -2
- data/gemlib/gel/stub.rb +20 -0
- data/lib/gel/catalog/common.rb +4 -2
- data/lib/gel/catalog/compact_index.rb +6 -10
- data/lib/gel/catalog/dependency_index.rb +10 -10
- data/lib/gel/catalog/legacy_index.rb +4 -6
- data/lib/gel/catalog/marshal_hacks.rb +2 -0
- data/lib/gel/catalog.rb +33 -52
- data/lib/gel/catalog_set.rb +100 -0
- data/lib/gel/command/help.rb +13 -2
- data/lib/gel/command/lock.rb +3 -3
- data/lib/gel/command/open.rb +24 -0
- data/lib/gel/command/shell_setup.rb +11 -8
- data/lib/gel/command/stub.rb +45 -2
- data/lib/gel/command/version.rb +7 -0
- data/lib/gel/command.rb +43 -6
- data/lib/gel/compatibility/rubygems.rb +10 -197
- data/lib/gel/compatibility.rb +2 -2
- data/lib/gel/config.rb +41 -7
- data/lib/gel/db.rb +93 -83
- data/lib/gel/direct_gem.rb +16 -4
- data/lib/gel/environment.rb +542 -249
- data/lib/gel/error.rb +156 -24
- data/lib/gel/gemfile_parser.rb +74 -12
- data/lib/gel/gemspec_parser.rb +26 -7
- data/lib/gel/git_catalog.rb +15 -3
- data/lib/gel/git_depot.rb +62 -28
- data/lib/gel/httpool.rb +5 -2
- data/lib/gel/installer.rb +61 -23
- data/lib/gel/lock_loader.rb +87 -112
- data/lib/gel/lock_parser.rb +23 -31
- data/lib/gel/locked_store.rb +30 -21
- data/lib/gel/multi_store.rb +13 -4
- data/lib/gel/null_solver.rb +67 -0
- data/lib/gel/package/abortable.rb +18 -0
- data/lib/gel/package/installer.rb +124 -49
- data/lib/gel/package.rb +21 -4
- data/lib/gel/path_catalog.rb +1 -1
- data/lib/gel/pinboard.rb +4 -2
- data/lib/gel/platform.rb +38 -0
- data/lib/gel/pub_grub/package.rb +67 -0
- data/lib/gel/pub_grub/preference_strategy.rb +10 -6
- data/lib/gel/pub_grub/solver.rb +37 -0
- data/lib/gel/pub_grub/source.rb +64 -92
- data/lib/gel/resolved_gem_set.rb +234 -0
- data/lib/gel/runtime.rb +3 -3
- data/lib/gel/set.rb +62 -0
- data/lib/gel/stdlib.rb +83 -0
- data/lib/gel/store.rb +94 -25
- data/lib/gel/store_catalog.rb +2 -2
- data/lib/gel/store_gem.rb +54 -6
- data/lib/gel/stub_set.rb +32 -2
- data/lib/gel/support/cgi_escape.rb +34 -0
- data/lib/gel/support/gem_platform.rb +0 -2
- data/lib/gel/support/sha512.rb +142 -0
- data/lib/gel/support/tar/tar_writer.rb +2 -2
- data/lib/gel/tail_file.rb +2 -1
- data/lib/gel/util.rb +108 -0
- data/lib/gel/vendor/pstore.rb +3 -0
- data/lib/gel/vendor/pub_grub.rb +3 -0
- data/lib/gel/vendor/ruby_digest.rb +3 -0
- data/lib/gel/vendor_catalog.rb +38 -0
- data/lib/gel/version.rb +1 -1
- data/lib/gel.rb +15 -0
- data/man/man1/gel-exec.1 +1 -1
- data/man/man1/gel-install.1 +1 -1
- data/man/man1/gel.1 +14 -1
- data/{lib/gel/compatibility → slib}/bundler/cli.rb +0 -0
- data/{lib/gel/compatibility → slib}/bundler/friendly_errors.rb +0 -0
- data/{lib/gel/compatibility/rubygems/dependency_installer.rb → slib/bundler/gem_helper.rb} +0 -0
- data/slib/bundler/gem_tasks.rb +0 -0
- data/{lib/gel/compatibility → slib}/bundler/setup.rb +0 -0
- data/{lib/gel/compatibility → slib}/bundler.rb +39 -3
- data/{lib/gel/compatibility → slib}/rubygems/command.rb +0 -0
- data/slib/rubygems/dependency_installer.rb +12 -0
- data/{lib/gel/compatibility → slib}/rubygems/gem_runner.rb +0 -0
- data/slib/rubygems/package.rb +6 -0
- data/slib/rubygems/package_task.rb +7 -0
- data/slib/rubygems/specification.rb +0 -0
- data/slib/rubygems/version.rb +0 -0
- data/slib/rubygems.rb +297 -0
- data/vendor/pstore/LICENSE.txt +22 -0
- data/vendor/pstore/lib/pstore.rb +488 -0
- data/vendor/pub_grub/LICENSE.txt +21 -0
- data/vendor/pub_grub/lib/pub_grub/assignment.rb +20 -0
- data/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +183 -0
- data/vendor/pub_grub/lib/pub_grub/failure_writer.rb +182 -0
- data/vendor/pub_grub/lib/pub_grub/incompatibility.rb +143 -0
- data/vendor/pub_grub/lib/pub_grub/package.rb +35 -0
- data/vendor/pub_grub/lib/pub_grub/partial_solution.rb +121 -0
- data/vendor/pub_grub/lib/pub_grub/rubygems.rb +45 -0
- data/vendor/pub_grub/lib/pub_grub/solve_failure.rb +17 -0
- data/vendor/pub_grub/lib/pub_grub/static_package_source.rb +53 -0
- data/vendor/pub_grub/lib/pub_grub/term.rb +105 -0
- data/vendor/pub_grub/lib/pub_grub/version.rb +3 -0
- data/vendor/pub_grub/lib/pub_grub/version_constraint.rb +124 -0
- data/vendor/pub_grub/lib/pub_grub/version_range.rb +399 -0
- data/vendor/pub_grub/lib/pub_grub/version_solver.rb +247 -0
- data/vendor/pub_grub/lib/pub_grub/version_union.rb +174 -0
- data/vendor/pub_grub/lib/pub_grub.rb +31 -0
- data/vendor/ruby-digest/UNLICENSE +24 -0
- data/vendor/ruby-digest/lib/ruby_digest.rb +812 -0
- metadata +95 -19
data/lib/gel/installer.rb
CHANGED
@@ -9,6 +9,9 @@ require_relative "package"
|
|
9
9
|
require_relative "package/installer"
|
10
10
|
|
11
11
|
class Gel::Installer
|
12
|
+
class SkipCatalog < Exception
|
13
|
+
end
|
14
|
+
|
12
15
|
DOWNLOAD_CONCURRENCY = 6
|
13
16
|
COMPILE_CONCURRENCY = 4
|
14
17
|
|
@@ -62,6 +65,8 @@ class Gel::Installer
|
|
62
65
|
end
|
63
66
|
|
64
67
|
def install_gem(catalogs, name, version)
|
68
|
+
raise "Refusing to install incompatible #{name.inspect}" if Gel::Environment::IGNORE_LIST.include?(name)
|
69
|
+
|
65
70
|
synchronize do
|
66
71
|
raise "catalogs is nil" if catalogs.nil?
|
67
72
|
@pending[name] += 1
|
@@ -72,6 +77,13 @@ class Gel::Installer
|
|
72
77
|
end
|
73
78
|
|
74
79
|
def load_git_gem(remote, revision, name)
|
80
|
+
dir = @git_depot.git_path(remote, revision)
|
81
|
+
|
82
|
+
if Dir.exist?(dir)
|
83
|
+
# already checked out; we assume it's also compiled if necessary
|
84
|
+
return
|
85
|
+
end
|
86
|
+
|
75
87
|
synchronize do
|
76
88
|
@pending[name] += 1
|
77
89
|
@download_pool.queue(name) do
|
@@ -81,22 +93,35 @@ class Gel::Installer
|
|
81
93
|
end
|
82
94
|
|
83
95
|
def work_git(remote, revision, name)
|
84
|
-
@git_depot.checkout(remote, revision)
|
96
|
+
dir = @git_depot.checkout(remote, revision)
|
85
97
|
|
86
|
-
|
87
|
-
|
88
|
-
|
98
|
+
if filename = ["#{dir}/#{name}.gemspec", "#{dir}/#{name}/#{name}.gemspec"].detect { |f| File.exist?(f) }
|
99
|
+
spec = Gel::GemspecParser.parse(File.read(filename), filename)
|
100
|
+
g = Gel::Package::Installer::GitCompiler.new(spec, store, dir)
|
89
101
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
102
|
+
known_dependencies g.spec.name => g.spec.runtime_dependencies.map(&:first)
|
103
|
+
if g.needs_compile?
|
104
|
+
synchronize do
|
105
|
+
add_weight name, 1000
|
106
|
+
|
107
|
+
@compile_pool.queue(g.spec.name) do
|
108
|
+
work_compile(g)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
else
|
112
|
+
work_install(g)
|
94
113
|
end
|
114
|
+
else
|
115
|
+
clear_pending(name)
|
95
116
|
end
|
117
|
+
end
|
96
118
|
|
119
|
+
def download_gem(catalogs, name, version)
|
97
120
|
catalogs.each do |catalog|
|
98
121
|
begin
|
99
|
-
|
122
|
+
if fpath = catalog.download_gem(name, version)
|
123
|
+
return fpath
|
124
|
+
end
|
100
125
|
rescue Net::HTTPExceptions
|
101
126
|
end
|
102
127
|
end
|
@@ -131,21 +156,34 @@ class Gel::Installer
|
|
131
156
|
end
|
132
157
|
end
|
133
158
|
|
134
|
-
|
135
|
-
|
159
|
+
begin
|
160
|
+
g.compile
|
161
|
+
rescue
|
162
|
+
clear_pending(g.spec.name)
|
163
|
+
raise
|
164
|
+
else
|
165
|
+
work_install(g)
|
166
|
+
end
|
136
167
|
end
|
137
168
|
|
138
169
|
def work_install(g)
|
139
|
-
|
140
|
-
|
141
|
-
|
170
|
+
if g.is_a?(Gel::Package::Installer::GemInstaller)
|
171
|
+
@messages << "Installing #{g.spec.name} (#{g.spec.version})\n"
|
172
|
+
g.install
|
173
|
+
end
|
174
|
+
|
175
|
+
clear_pending(g.spec.name)
|
176
|
+
end
|
177
|
+
|
178
|
+
def clear_pending(name)
|
179
|
+
@pending[name] -= 1
|
142
180
|
|
143
181
|
synchronize do
|
144
182
|
compile_recheck, @compile_waiting = @compile_waiting, []
|
145
183
|
|
146
|
-
compile_recheck.each do |
|
147
|
-
@compile_pool.queue(
|
148
|
-
work_compile(
|
184
|
+
compile_recheck.each do |gem|
|
185
|
+
@compile_pool.queue(gem.spec.name) do
|
186
|
+
work_compile(gem)
|
149
187
|
end
|
150
188
|
end
|
151
189
|
end
|
@@ -202,7 +240,7 @@ class Gel::Installer
|
|
202
240
|
if output
|
203
241
|
output.write "Installed #{@download_pool.count - errors.size} of #{@download_pool.count} gems\n\nErrors encountered with #{errors.size} gems:\n\n"
|
204
242
|
errors.each do |(_, name), exception|
|
205
|
-
output.write "#{name}\n
|
243
|
+
output.write "#{name}\n#{exception.to_s.gsub(/^(?=.)/, " ")}\n\n"
|
206
244
|
end
|
207
245
|
end
|
208
246
|
|
@@ -218,12 +256,12 @@ class Gel::Installer
|
|
218
256
|
|
219
257
|
def compile_ready?(name)
|
220
258
|
@dependencies[name].all? do |dep|
|
221
|
-
if @
|
222
|
-
|
223
|
-
elsif @download_pool.errors.any? { |(_, failed_name), ex| failed_name == dep }
|
224
|
-
raise "Depends on #{dep.inspect}, which failed to download"
|
259
|
+
if @download_pool.errors.any? { |(_, failed_name), ex| failed_name == dep }
|
260
|
+
raise Gel::Error::ExtensionDependencyError.new(dependency: dep, failure: "download")
|
225
261
|
elsif @compile_pool.errors.any? { |(_, failed_name), ex| failed_name == dep }
|
226
|
-
raise
|
262
|
+
raise Gel::Error::ExtensionDependencyError.new(dependency: dep, failure: "compile")
|
263
|
+
elsif @pending[dep] == 0
|
264
|
+
compile_ready?(dep)
|
227
265
|
else
|
228
266
|
false
|
229
267
|
end
|
data/lib/gel/lock_loader.rb
CHANGED
@@ -1,64 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "resolved_gem_set"
|
4
|
+
require_relative "git_catalog"
|
5
|
+
require_relative "path_catalog"
|
6
|
+
|
7
|
+
require_relative "support/gem_platform"
|
8
|
+
|
3
9
|
class Gel::LockLoader
|
4
|
-
attr_reader :filename
|
5
10
|
attr_reader :gemfile
|
6
11
|
|
7
|
-
def initialize(
|
8
|
-
@
|
12
|
+
def initialize(gem_set, gemfile = nil)
|
13
|
+
@gem_set = gem_set
|
9
14
|
@gemfile = gemfile
|
10
15
|
end
|
11
16
|
|
12
|
-
def lock_content
|
13
|
-
@lock_content ||= Gel::LockParser.new.parse(File.read(filename))
|
14
|
-
end
|
15
|
-
|
16
|
-
def each_gem
|
17
|
-
lock_content.each do |(section, body)|
|
18
|
-
case section
|
19
|
-
when "GEM", "PATH", "GIT"
|
20
|
-
specs = body["specs"]
|
21
|
-
specs.each do |gem_spec, dep_specs|
|
22
|
-
gem_spec =~ /\A(.+) \(([^-]+)(?:-(.+))?\)\z/
|
23
|
-
name, version, platform = $1, $2, $3
|
24
|
-
|
25
|
-
if dep_specs
|
26
|
-
deps = dep_specs.map do |spec|
|
27
|
-
spec =~ /\A(.+?)(?: \((.+)\))?\z/
|
28
|
-
[$1, $2 ? $2.split(", ") : []]
|
29
|
-
end
|
30
|
-
else
|
31
|
-
deps = []
|
32
|
-
end
|
33
|
-
|
34
|
-
sym =
|
35
|
-
case section
|
36
|
-
when "GEM"; :gem
|
37
|
-
when "PATH"; :path
|
38
|
-
when "GIT"; :git
|
39
|
-
end
|
40
|
-
yield sym, body, name, version, platform, deps
|
41
|
-
end
|
42
|
-
when "PLATFORMS", "DEPENDENCIES"
|
43
|
-
when "RUBY VERSION"
|
44
|
-
when "BUNDLED WITH"
|
45
|
-
else
|
46
|
-
warn "Unknown lockfile section #{section.inspect}"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def bundler_version
|
52
|
-
_, (version,) = lock_content.assoc("BUNDLED WITH")
|
53
|
-
version
|
54
|
-
end
|
55
|
-
|
56
17
|
def gem_names
|
57
|
-
|
58
|
-
each_gem do |section, body, name, version, platform, deps|
|
59
|
-
names << name
|
60
|
-
end
|
61
|
-
names
|
18
|
+
@gem_set.gem_names
|
62
19
|
end
|
63
20
|
|
64
21
|
def activate(env, base_store, install: false, output: nil)
|
@@ -71,95 +28,113 @@ class Gel::LockLoader
|
|
71
28
|
installer = Gel::Installer.new(base_store)
|
72
29
|
end
|
73
30
|
|
74
|
-
|
75
|
-
top_gems = []
|
31
|
+
gems_to_process = []
|
76
32
|
if gemfile && env
|
77
|
-
gemfile.gems.each do |name, *|
|
78
|
-
filtered_gems[name] = false
|
79
|
-
end
|
80
33
|
env.filtered_gems(gemfile.gems).each do |name, *|
|
81
|
-
|
82
|
-
filtered_gems[name] = true
|
83
|
-
end
|
84
|
-
elsif pair = lock_content.assoc("DEPENDENCIES")
|
85
|
-
_, list = pair
|
86
|
-
top_gems = list.map { |name| name.split(" ", 2)[0].chomp("!") }
|
87
|
-
top_gems.each do |name|
|
88
|
-
filtered_gems[name] = true
|
34
|
+
gems_to_process << name
|
89
35
|
end
|
36
|
+
elsif list = @gem_set.dependency_names
|
37
|
+
gems_to_process = list
|
90
38
|
end
|
91
39
|
|
92
|
-
|
93
|
-
|
94
|
-
next if env && !env.platform?(platform)
|
95
|
-
|
96
|
-
gems[name] = [section, body, version, platform, deps]
|
40
|
+
local_platform = Gel::Support::GemPlatform.local
|
41
|
+
all_gems = @gem_set.gems
|
97
42
|
|
98
|
-
|
43
|
+
deferred_direct_gem = lambda do |dir, name, version|
|
44
|
+
-> { Gel::DirectGem.new(dir, name, version) }
|
99
45
|
end
|
100
46
|
|
101
|
-
|
102
|
-
|
103
|
-
next
|
104
|
-
|
105
|
-
walk[dep_name] unless filtered_gems[dep_name]
|
106
|
-
end
|
107
|
-
end
|
47
|
+
processed_gems = {}
|
48
|
+
while name = gems_to_process.shift
|
49
|
+
next if processed_gems[name]
|
50
|
+
processed_gems[name] = true
|
108
51
|
|
109
|
-
|
52
|
+
next if Gel::Environment::IGNORE_LIST.include?(name)
|
110
53
|
|
111
|
-
|
112
|
-
require_relative "work_pool"
|
54
|
+
next unless all_versions = all_gems[name]
|
113
55
|
|
114
|
-
|
115
|
-
|
56
|
+
resolved_gems = all_versions.select do |rg|
|
57
|
+
local_platform =~ rg.platform || rg.platform.nil?
|
58
|
+
end.sort_by { |rg| rg.platform&.size || 0 }.reverse
|
116
59
|
|
117
|
-
|
118
|
-
next unless filtered_gems[name]
|
60
|
+
next if resolved_gems.empty?
|
119
61
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
62
|
+
resolved_gem = resolved_gems.first
|
63
|
+
|
64
|
+
|
65
|
+
case resolved_gem.catalog
|
66
|
+
when Gel::GitCatalog
|
67
|
+
dir = resolved_gem.catalog.path
|
126
68
|
|
127
|
-
|
128
|
-
|
129
|
-
if section == :git
|
130
|
-
remote = body["remote"].first
|
131
|
-
revision = body["revision"].first
|
69
|
+
installer.known_dependencies name => resolved_gem.deps.map(&:first) if installer
|
70
|
+
installer&.load_git_gem(resolved_gem.catalog.remote, resolved_gem.catalog.revision, name)
|
132
71
|
|
133
|
-
|
134
|
-
|
135
|
-
|
72
|
+
locks[name] = deferred_direct_gem.call(dir, name, resolved_gem.version)
|
73
|
+
when Gel::PathCatalog
|
74
|
+
path = resolved_gem.catalog.path
|
136
75
|
|
137
|
-
|
138
|
-
|
76
|
+
dir = File.expand_path(path, File.dirname(@gem_set.filename))
|
77
|
+
|
78
|
+
installer.known_dependencies name => resolved_gem.deps.map(&:first) if installer
|
79
|
+
locks[name] = Gel::DirectGem.new(dir, name, resolved_gem.version)
|
80
|
+
else
|
81
|
+
unless resolved_gem = resolved_gems.find { |rg| base_store.gem?(name, rg.version, rg.platform) }
|
82
|
+
if installer
|
83
|
+
require_relative "catalog"
|
84
|
+
|
85
|
+
catalogs = @gem_set.server_catalogs
|
86
|
+
|
87
|
+
if resolved_gems.size > 1
|
88
|
+
skipped_matches = []
|
89
|
+
|
90
|
+
catalog_infos = catalogs.map { |c| c.gem_info(name) }
|
91
|
+
resolved_gems.each do |rg|
|
92
|
+
catalog_infos.each do |info|
|
93
|
+
s = rg.platform ? "#{rg.version}-#{rg.platform}" : rg.version
|
94
|
+
if i = info[s]
|
95
|
+
if i[:ruby] && !Gel::Support::GemRequirement.new(i[:ruby].split("&")).satisfied_by?(Gel::Support::GemVersion.new(RUBY_VERSION))
|
96
|
+
skipped_matches << s
|
97
|
+
else
|
98
|
+
resolved_gem = rg
|
99
|
+
break
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
break if resolved_gem
|
105
|
+
end
|
106
|
+
|
107
|
+
if resolved_gem.nil?
|
108
|
+
raise UnsatisfiableRubyVersionError.new(name: name, running: RUBY_VERSION, attempted_platforms: skipped_matches)
|
109
|
+
end
|
110
|
+
else
|
111
|
+
resolved_gem = resolved_gems.first
|
139
112
|
end
|
113
|
+
|
114
|
+
installer.known_dependencies name => resolved_gem.deps.map(&:first)
|
115
|
+
installer.install_gem(catalogs, name, resolved_gem.platform ? "#{resolved_gem.version}-#{resolved_gem.platform}" : resolved_gem.version)
|
140
116
|
else
|
141
|
-
|
117
|
+
raise Gel::Error::MissingGemError.new(name: name)
|
142
118
|
end
|
143
|
-
|
144
|
-
locks[name] = Gel::DirectGem.new(dir, name, version)
|
145
119
|
end
|
120
|
+
|
121
|
+
locks[name] = resolved_gem.version.to_s
|
146
122
|
end
|
147
123
|
|
148
|
-
installer.wait(output) if installer
|
149
124
|
|
150
|
-
|
151
|
-
|
125
|
+
resolved_gem.deps.map(&:first).each do |dep_name|
|
126
|
+
gems_to_process.unshift dep_name
|
152
127
|
end
|
153
128
|
end
|
154
129
|
|
155
|
-
|
156
|
-
|
157
|
-
if env
|
158
|
-
env.open(locked_store)
|
130
|
+
installer.wait(output) if installer
|
159
131
|
|
160
|
-
|
132
|
+
locks.each do |name, locked|
|
133
|
+
locks[name] = locked.call if locked.is_a?(Proc)
|
161
134
|
end
|
162
135
|
|
136
|
+
locked_store.lock(locks)
|
137
|
+
|
163
138
|
locked_store
|
164
139
|
end
|
165
140
|
end
|
data/lib/gel/lock_parser.rb
CHANGED
@@ -1,34 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "strscan"
|
4
|
-
|
5
3
|
class Gel::LockParser
|
6
|
-
def parse(
|
4
|
+
def parse(input)
|
7
5
|
sections = []
|
8
6
|
|
9
|
-
|
10
|
-
while
|
11
|
-
section
|
7
|
+
input = input.dup
|
8
|
+
while input.sub!(/\A(\w.+)\n/, "")
|
9
|
+
section = $1
|
10
|
+
|
12
11
|
case section
|
13
12
|
when "GIT", "PATH", "GEM"
|
14
13
|
content = {}
|
15
|
-
while
|
16
|
-
label =
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
(content[label] ||= []) << value
|
21
|
-
else
|
22
|
-
scanner.skip(/\n/)
|
14
|
+
while input.sub!(/\A {2}\b([^:]+):(\s)/, "")
|
15
|
+
label = $1
|
16
|
+
separator = $2
|
17
|
+
|
18
|
+
if separator == "\n"
|
23
19
|
value = []
|
24
|
-
while
|
25
|
-
entry =
|
26
|
-
scanner.skip(/\n/)
|
20
|
+
while input.sub!(/\A {4}\b(.*)\n/, "")
|
21
|
+
entry = $1
|
27
22
|
children = []
|
28
|
-
while
|
29
|
-
|
30
|
-
children << child
|
31
|
-
scanner.skip(/\n/)
|
23
|
+
while input.sub!(/\A {6}\b(.*)\n/, "")
|
24
|
+
children << $1
|
32
25
|
end
|
33
26
|
if children.empty?
|
34
27
|
value << [entry]
|
@@ -37,24 +30,23 @@ class Gel::LockParser
|
|
37
30
|
end
|
38
31
|
end
|
39
32
|
content[label] = value
|
33
|
+
else
|
34
|
+
input.sub!(/\A(.*)\n/, "")
|
35
|
+
(content[label] ||= []) << $1
|
40
36
|
end
|
41
37
|
end
|
42
38
|
when "PLATFORMS", "DEPENDENCIES"
|
43
39
|
content = []
|
44
|
-
while
|
45
|
-
|
46
|
-
content << entry
|
47
|
-
scanner.skip(/\n/)
|
40
|
+
while input.sub!(/\A {2}\b(.*)\n/, "")
|
41
|
+
content << $1
|
48
42
|
end
|
49
|
-
when "BUNDLED WITH"
|
43
|
+
when "BUNDLED WITH", "RUBY VERSION"
|
50
44
|
content = []
|
51
|
-
while
|
52
|
-
|
53
|
-
content << entry
|
54
|
-
scanner.skip(/\n/)
|
45
|
+
while input.sub!(/\A {3}\b(.*)\n/, "")
|
46
|
+
content << $1
|
55
47
|
end
|
56
48
|
end
|
57
|
-
|
49
|
+
input.sub!(/\A\n+/, "")
|
58
50
|
|
59
51
|
sections << [section, content]
|
60
52
|
end
|
data/lib/gel/locked_store.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
class Gel::LockedStore
|
4
4
|
attr_reader :inner
|
5
|
+
attr_reader :locked_versions
|
5
6
|
|
6
7
|
def initialize(inner)
|
7
8
|
@inner = inner
|
@@ -11,6 +12,10 @@ class Gel::LockedStore
|
|
11
12
|
@full_cache = false
|
12
13
|
end
|
13
14
|
|
15
|
+
def stub_set
|
16
|
+
@inner.stub_set
|
17
|
+
end
|
18
|
+
|
14
19
|
def paths
|
15
20
|
@inner.paths
|
16
21
|
end
|
@@ -20,7 +25,7 @@ class Gel::LockedStore
|
|
20
25
|
end
|
21
26
|
|
22
27
|
def inspect
|
23
|
-
content = @locked_versions.map { |name, version| "#{name}=#{version.is_a?(String) ? version : version.root}" }
|
28
|
+
content = (@locked_versions || []).map { |name, version| "#{name}=#{version.is_a?(String) ? version : version.root}" }
|
24
29
|
content = ["(none)"] if content.empty?
|
25
30
|
content.sort!
|
26
31
|
|
@@ -33,8 +38,8 @@ class Gel::LockedStore
|
|
33
38
|
inner_versions = {}
|
34
39
|
locks.each do |name, version|
|
35
40
|
if version.is_a?(Gel::StoreGem)
|
36
|
-
version.libs do |file, subdir|
|
37
|
-
@lib_cache[file] << [version, subdir]
|
41
|
+
version.libs do |file, subdir, ext|
|
42
|
+
@lib_cache[file] << [version, subdir, ext]
|
38
43
|
end
|
39
44
|
else
|
40
45
|
inner_versions[name] = version
|
@@ -43,8 +48,8 @@ class Gel::LockedStore
|
|
43
48
|
|
44
49
|
g = @inner.gems(inner_versions)
|
45
50
|
@inner.libs_for_gems(inner_versions) do |name, version, subs|
|
46
|
-
subs.each do |subdir, files|
|
47
|
-
v = [g[name], subdir]
|
51
|
+
subs.each do |(subdir, ext), files|
|
52
|
+
v = [g[name], subdir, ext]
|
48
53
|
files.each do |file|
|
49
54
|
@lib_cache[file] << v
|
50
55
|
end
|
@@ -83,29 +88,33 @@ class Gel::LockedStore
|
|
83
88
|
end
|
84
89
|
|
85
90
|
def gems_for_lib(file)
|
86
|
-
|
87
|
-
c.each { |gem, subdir| yield gem, subdir }
|
88
|
-
return
|
89
|
-
end
|
91
|
+
search_name, search_ext = Gel::Util.split_filename_for_require(file)
|
90
92
|
|
91
|
-
hits =
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
93
|
+
unless hits = @lib_cache.fetch(search_name, nil)
|
94
|
+
hits = []
|
95
|
+
|
96
|
+
unless @full_cache
|
97
|
+
@inner.gems_for_lib(search_name) do |gem, subdir, ext|
|
98
|
+
if locked?(gem)
|
99
|
+
hits << [gem, subdir, ext]
|
100
|
+
end
|
97
101
|
end
|
98
102
|
end
|
99
|
-
end
|
100
103
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
104
|
+
locked_gems.each do |gem|
|
105
|
+
gem.entries_for_lib(search_name) do |subdir, ext|
|
106
|
+
hits << [gem, subdir, ext]
|
107
|
+
end
|
105
108
|
end
|
109
|
+
|
110
|
+
@lib_cache[file] = hits
|
106
111
|
end
|
107
112
|
|
108
|
-
|
113
|
+
hits.each do |gem, subdir, ext|
|
114
|
+
if Gel::Util.ext_matches_requested?(ext, search_ext)
|
115
|
+
yield gem, subdir, ext
|
116
|
+
end
|
117
|
+
end
|
109
118
|
end
|
110
119
|
|
111
120
|
def each(gem_name = nil)
|
data/lib/gel/multi_store.rb
CHANGED
@@ -10,12 +10,21 @@ class Gel::MultiStore
|
|
10
10
|
attr_reader :monitor
|
11
11
|
|
12
12
|
def initialize(root, stores)
|
13
|
-
@root = File.realpath(File.expand_path(root))
|
13
|
+
@root = root && File.realpath(File.expand_path(root))
|
14
14
|
@stores = stores
|
15
15
|
|
16
16
|
@monitor = Monitor.new
|
17
17
|
end
|
18
18
|
|
19
|
+
def marshal_dump
|
20
|
+
[@root, @stores]
|
21
|
+
end
|
22
|
+
|
23
|
+
def marshal_load(v)
|
24
|
+
@root, @stores = v
|
25
|
+
@monitor = Monitor.new
|
26
|
+
end
|
27
|
+
|
19
28
|
def stub_set
|
20
29
|
@stub_set ||= Gel::StubSet.new(@root)
|
21
30
|
end
|
@@ -47,8 +56,8 @@ class Gel::MultiStore
|
|
47
56
|
|
48
57
|
def gems_for_lib(file)
|
49
58
|
@stores.each do |_, store|
|
50
|
-
store.gems_for_lib(file) do |gem, subdir|
|
51
|
-
yield gem, subdir
|
59
|
+
store.gems_for_lib(file) do |gem, subdir, ext|
|
60
|
+
yield gem, subdir, ext
|
52
61
|
end
|
53
62
|
end
|
54
63
|
end
|
@@ -73,7 +82,7 @@ class Gel::MultiStore
|
|
73
82
|
result = {}
|
74
83
|
|
75
84
|
@stores.each do |_, store|
|
76
|
-
result.update(store.gems(name_version_pairs)) do |l, r|
|
85
|
+
result.update(store.gems(name_version_pairs)) do |_, l, r|
|
77
86
|
l
|
78
87
|
end
|
79
88
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Gel::NullSolver
|
4
|
+
NullPackage = Struct.new(:name, :platform)
|
5
|
+
|
6
|
+
def initialize(gemfile:, catalog_set:, platforms:)
|
7
|
+
@gemfile = gemfile
|
8
|
+
@catalog_set = catalog_set
|
9
|
+
@platforms = platforms
|
10
|
+
|
11
|
+
@platform = @platforms.first
|
12
|
+
|
13
|
+
@packages = Hash.new { |h, k| h[k] = NullPackage.new(k, @platform) }
|
14
|
+
|
15
|
+
@solution = {}
|
16
|
+
@constraints = Hash.new { |h, k| h[k] = [] }
|
17
|
+
|
18
|
+
@gemfile.gems.each do |name, constraints, options|
|
19
|
+
raise "NullSolver can't apply platform constraints" if options[:platforms]
|
20
|
+
@constraints[name].concat(constraints || [])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def solved?
|
25
|
+
gems_to_solve.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def work
|
29
|
+
name = gems_to_solve.first
|
30
|
+
|
31
|
+
req = Gel::Support::GemRequirement.new(@constraints[name])
|
32
|
+
|
33
|
+
choice =
|
34
|
+
@catalog_set.entries_for(@packages[name]).map(&:gem_version).
|
35
|
+
sort_by { |v| [v.prerelease? ? 0 : 1, v] }.
|
36
|
+
reverse.find { |v| req.satisfied_by?(v) }
|
37
|
+
|
38
|
+
if choice.nil?
|
39
|
+
raise "Failed to resolve #{name.inspect} (#{req.inspect}) given #{@solution.inspect}"
|
40
|
+
end
|
41
|
+
|
42
|
+
@solution[name] = choice
|
43
|
+
|
44
|
+
@catalog_set.dependencies_for(@packages[name], choice).each do |dep_name, constraints|
|
45
|
+
if @solution[dep_name]
|
46
|
+
new_req = Gel::Support::GemRequirement.new(constraints)
|
47
|
+
unless new_req.satisfied_by?(@solution[dep_name])
|
48
|
+
raise "Already chose #{dep_name.inspect} #{@solution[dep_name]}, which is incompatible with #{name.inspect} #{choice.inspect} (wants #{new_req})"
|
49
|
+
end
|
50
|
+
else
|
51
|
+
@constraints[name].concat(constraints || [])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def each_resolved_package
|
57
|
+
@solution.each do |name, version|
|
58
|
+
yield @packages[name], version
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def gems_to_solve
|
65
|
+
@constraints.keys - @solution.keys
|
66
|
+
end
|
67
|
+
end
|