gel 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/exe/gel +13 -0
- data/lib/gel.rb +22 -0
- data/lib/gel/catalog.rb +153 -0
- data/lib/gel/catalog/common.rb +82 -0
- data/lib/gel/catalog/compact_index.rb +152 -0
- data/lib/gel/catalog/dependency_index.rb +125 -0
- data/lib/gel/catalog/legacy_index.rb +157 -0
- data/lib/gel/catalog/marshal_hacks.rb +16 -0
- data/lib/gel/command.rb +86 -0
- data/lib/gel/command/config.rb +11 -0
- data/lib/gel/command/env.rb +7 -0
- data/lib/gel/command/exec.rb +66 -0
- data/lib/gel/command/help.rb +7 -0
- data/lib/gel/command/install.rb +7 -0
- data/lib/gel/command/install_gem.rb +16 -0
- data/lib/gel/command/lock.rb +34 -0
- data/lib/gel/command/ruby.rb +10 -0
- data/lib/gel/command/shell_setup.rb +25 -0
- data/lib/gel/command/stub.rb +12 -0
- data/lib/gel/command/update.rb +11 -0
- data/lib/gel/compatibility.rb +4 -0
- data/lib/gel/compatibility/bundler.rb +54 -0
- data/lib/gel/compatibility/bundler/cli.rb +6 -0
- data/lib/gel/compatibility/bundler/friendly_errors.rb +3 -0
- data/lib/gel/compatibility/bundler/setup.rb +4 -0
- data/lib/gel/compatibility/rubygems.rb +192 -0
- data/lib/gel/compatibility/rubygems/command.rb +4 -0
- data/lib/gel/compatibility/rubygems/dependency_installer.rb +0 -0
- data/lib/gel/compatibility/rubygems/gem_runner.rb +6 -0
- data/lib/gel/config.rb +80 -0
- data/lib/gel/db.rb +294 -0
- data/lib/gel/direct_gem.rb +29 -0
- data/lib/gel/environment.rb +592 -0
- data/lib/gel/error.rb +104 -0
- data/lib/gel/gemfile_parser.rb +144 -0
- data/lib/gel/gemspec_parser.rb +95 -0
- data/lib/gel/git_catalog.rb +38 -0
- data/lib/gel/git_depot.rb +119 -0
- data/lib/gel/httpool.rb +148 -0
- data/lib/gel/installer.rb +251 -0
- data/lib/gel/lock_loader.rb +164 -0
- data/lib/gel/lock_parser.rb +64 -0
- data/lib/gel/locked_store.rb +126 -0
- data/lib/gel/multi_store.rb +96 -0
- data/lib/gel/package.rb +156 -0
- data/lib/gel/package/inspector.rb +23 -0
- data/lib/gel/package/installer.rb +267 -0
- data/lib/gel/path_catalog.rb +44 -0
- data/lib/gel/pinboard.rb +140 -0
- data/lib/gel/pub_grub/preference_strategy.rb +82 -0
- data/lib/gel/pub_grub/source.rb +153 -0
- data/lib/gel/runtime.rb +27 -0
- data/lib/gel/store.rb +205 -0
- data/lib/gel/store_catalog.rb +31 -0
- data/lib/gel/store_gem.rb +80 -0
- data/lib/gel/stub_set.rb +51 -0
- data/lib/gel/support/gem_platform.rb +225 -0
- data/lib/gel/support/gem_requirement.rb +264 -0
- data/lib/gel/support/gem_version.rb +398 -0
- data/lib/gel/support/tar.rb +13 -0
- data/lib/gel/support/tar/tar_header.rb +229 -0
- data/lib/gel/support/tar/tar_reader.rb +123 -0
- data/lib/gel/support/tar/tar_reader/entry.rb +154 -0
- data/lib/gel/support/tar/tar_writer.rb +339 -0
- data/lib/gel/tail_file.rb +205 -0
- data/lib/gel/version.rb +5 -0
- data/lib/gel/work_pool.rb +143 -0
- data/man/man1/gel-exec.1 +16 -0
- data/man/man1/gel-install.1 +16 -0
- data/man/man1/gel.1 +30 -0
- metadata +131 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Gel::Command::InstallGem < Gel::Command
|
4
|
+
def run(command_line)
|
5
|
+
gem_name, gem_version = command_line
|
6
|
+
|
7
|
+
require_relative "../catalog"
|
8
|
+
require_relative "../work_pool"
|
9
|
+
|
10
|
+
Gel::WorkPool.new(2) do |work_pool|
|
11
|
+
catalog = Gel::Catalog.new("https://rubygems.org", work_pool: work_pool)
|
12
|
+
|
13
|
+
Gel::Environment.install_gem([catalog], gem_name, gem_version, output: $stderr)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Gel::Command::Lock < Gel::Command
|
4
|
+
def run(command_line)
|
5
|
+
options = {}
|
6
|
+
|
7
|
+
mode = :hold
|
8
|
+
strict = false
|
9
|
+
overrides = {}
|
10
|
+
|
11
|
+
until command_line.empty?
|
12
|
+
case argument = command_line.shift
|
13
|
+
when "--strict"; strict = true
|
14
|
+
when "--major"; mode = :major
|
15
|
+
when "--minor"; mode = :minor
|
16
|
+
when "--patch"; mode = :patch
|
17
|
+
when "--hold"; mode = :hold
|
18
|
+
when /\A--lockfile(?:=(.*))?\z/
|
19
|
+
options[:lockfile] = $1 || command_line.shift
|
20
|
+
when /\A((?!-)[A-Za-z0-9_-]+)(?:(?:[\ :\/]|(?=[<>~=]))([<>~=,\ 0-9A-Za-z.-]+))?\z/x
|
21
|
+
overrides[$1] = Gel::Support::GemRequirement.new($2 ? $2.split(/\s+(?=[0-9])|\s*,\s*/) : [])
|
22
|
+
else
|
23
|
+
raise "Unknown argument #{argument.inspect}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require_relative "../pub_grub/preference_strategy"
|
28
|
+
options[:preference_strategy] = lambda do |loader|
|
29
|
+
Gel::PubGrub::PreferenceStrategy.new(loader, overrides, bump: mode, strict: strict)
|
30
|
+
end
|
31
|
+
|
32
|
+
Gel::Environment.lock(output: $stderr, **options)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Gel::Command::ShellSetup < Gel::Command
|
4
|
+
def run(command_line)
|
5
|
+
require "shellwords"
|
6
|
+
|
7
|
+
variables = []
|
8
|
+
|
9
|
+
bin_dir = File.expand_path("~/.local/gel/bin")
|
10
|
+
unless ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).include?(bin_dir)
|
11
|
+
puts "PATH=\"#{Shellwords.shellescape bin_dir}#{File::PATH_SEPARATOR}$PATH\""
|
12
|
+
variables << "PATH"
|
13
|
+
end
|
14
|
+
|
15
|
+
lib_dir = File.expand_path("../compatibility", __dir__)
|
16
|
+
unless ENV.fetch("RUBYLIB", "").split(File::PATH_SEPARATOR).include?(lib_dir)
|
17
|
+
puts "RUBYLIB=\"#{Shellwords.shellescape lib_dir}:$RUBYLIB\""
|
18
|
+
variables << "RUBYLIB"
|
19
|
+
end
|
20
|
+
|
21
|
+
unless variables.empty?
|
22
|
+
puts "export #{variables.join(" ")}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Gel::Command::Stub < Gel::Command
|
4
|
+
def run(command_line)
|
5
|
+
stub_command, _path, *arguments = command_line
|
6
|
+
|
7
|
+
command = Gel::Command::Exec.new
|
8
|
+
command.run([stub_command, *arguments], from_stub: true)
|
9
|
+
ensure
|
10
|
+
self.reraise = command.reraise if command
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Gel::Command::Update < Gel::Command
|
4
|
+
def run(command_line)
|
5
|
+
# Mega update mode
|
6
|
+
command_line = ["--major"] if command_line.empty?
|
7
|
+
|
8
|
+
Gel::Command::Lock.new.run(command_line)
|
9
|
+
Gel::Environment.activate(install: true, output: $stderr)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
def self.setup
|
5
|
+
Gel::Environment.activate(output: $stderr)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.require(*groups)
|
9
|
+
Gel::Environment.require_groups(*groups)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.default_lockfile
|
13
|
+
Pathname.new(Gel::Environment.lockfile_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
module Rubygems
|
17
|
+
def self.loaded_specs(gem_name)
|
18
|
+
Gem::Specification.new(Gel::Environment.activated_gems[gem_name])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# This is only emulated for bin/spring: we really don't want to try to
|
23
|
+
# actually reproduce Bundler's API
|
24
|
+
class LockfileParser
|
25
|
+
def initialize(content)
|
26
|
+
end
|
27
|
+
|
28
|
+
def specs
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.rubygems
|
34
|
+
Rubygems
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.with_original_env
|
38
|
+
# TODO
|
39
|
+
yield
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.with_clean_env
|
43
|
+
# TODO
|
44
|
+
yield
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.settings
|
48
|
+
if gemfile = Gel::Environment.gemfile
|
49
|
+
{ "gemfile" => gemfile.filename }
|
50
|
+
else
|
51
|
+
{}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
# We assume this file is only required by the `bundle` executable: if we
|
2
|
+
# get here, we need to re-exec it without Gel on the path, to ensure it
|
3
|
+
# has a full and proper Rubygems environment to work with.
|
4
|
+
|
5
|
+
ENV["RUBYLIB"] = Gel::Environment.original_rubylib
|
6
|
+
exec RbConfig.ruby, "--", $0, *ARGV
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The goal here is not to be a full drop-in replacement of RubyGems'
|
4
|
+
# API.
|
5
|
+
#
|
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 g = Gel::Environment.activated_gems[gem_name]
|
139
|
+
Gel::Environment.gem g.name, version if version
|
140
|
+
elsif g = Gel::Environment.find_gem(gem_name, *version) do |g|
|
141
|
+
g.executables.include?(bin_name)
|
142
|
+
end
|
143
|
+
|
144
|
+
Gel::Environment.gem g.name, g.version
|
145
|
+
elsif g = Gel::Environment.find_gem(gem_name, *version)
|
146
|
+
raise "#{g.name} (#{g.version}) doesn't contain executable #{bin_name.inspect}"
|
147
|
+
elsif version && Gel::Environment.find_gem(gem_name)
|
148
|
+
raise "#{gem_name} (#{version}) not available"
|
149
|
+
else
|
150
|
+
raise "Unknown gem #{gem_name.inspect}"
|
151
|
+
end
|
152
|
+
|
153
|
+
Gel::Environment.find_executable(bin_name, g.name, g.version)
|
154
|
+
rescue => ex
|
155
|
+
# This method may be our entry-point, if we're being invoked by a
|
156
|
+
# rubygems binstub. Detect that situation, and provide nicer error
|
157
|
+
# reporting.
|
158
|
+
|
159
|
+
raise unless locations = caller_locations(2, 2)
|
160
|
+
raise unless locations.size == 1
|
161
|
+
raise unless path = locations.first.absolute_path
|
162
|
+
raise unless File.exist?(path) && File.readable?(path)
|
163
|
+
raise unless File.open(path, "rb") { |f| f.read(1024).include?("\n# This file was generated by RubyGems.\n") }
|
164
|
+
|
165
|
+
require_relative "../command"
|
166
|
+
Gel::Command.handle_error(ex)
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.bin_path(gem_name, bin_name, version = nil)
|
170
|
+
if g = Gel::Environment.activated_gems[gem_name]
|
171
|
+
Gel::Environment.gem g.name, version if version
|
172
|
+
|
173
|
+
Gel::Environment.find_executable(bin_name, g.name, g.version)
|
174
|
+
elsif Gel::Environment.find_gem(gem_name)
|
175
|
+
raise "Gem #{gem_name.inspect} is not active"
|
176
|
+
else
|
177
|
+
raise "Unknown gem #{gem_name.inspect}"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def gem(*args)
|
183
|
+
Gel::Environment.gem(*args)
|
184
|
+
end
|
185
|
+
private :gem
|
186
|
+
|
187
|
+
def require(path)
|
188
|
+
super Gel::Environment.resolve_gem_path(path)
|
189
|
+
end
|
190
|
+
private :require
|
191
|
+
|
192
|
+
require "rubygems/deprecate"
|
File without changes
|
@@ -0,0 +1,6 @@
|
|
1
|
+
# We assume this file is only required by the `gem` executable: if we
|
2
|
+
# get here, we need to re-exec it without Gel on the path, to ensure it
|
3
|
+
# has a full and proper Rubygems environment to work with.
|
4
|
+
|
5
|
+
ENV["RUBYLIB"] = Gel::Environment.original_rubylib
|
6
|
+
exec RbConfig.ruby, "--", $0, *ARGV
|
data/lib/gel/config.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Gel::Config
|
4
|
+
def initialize
|
5
|
+
@root = File.expand_path("~/.config/gel")
|
6
|
+
@path = File.join(@root, "config")
|
7
|
+
@config = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def config
|
11
|
+
@config ||= read
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](group = nil, key)
|
15
|
+
if group.nil?
|
16
|
+
group, key = key.split(".", 2)
|
17
|
+
end
|
18
|
+
|
19
|
+
(group ? (config[group.to_s] || {}) : config)[key.to_s]
|
20
|
+
end
|
21
|
+
|
22
|
+
def []=(group = nil, key, value)
|
23
|
+
if group.nil?
|
24
|
+
group, key = key.split(".", 2)
|
25
|
+
end
|
26
|
+
|
27
|
+
(group ? (config[group.to_s] ||= {}) : config)[key.to_s] = value.to_s
|
28
|
+
|
29
|
+
write(config)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def read
|
35
|
+
result = {}
|
36
|
+
if File.exist?(@path)
|
37
|
+
context = nil
|
38
|
+
File.read(@path).each_line do |line|
|
39
|
+
line.chomp!
|
40
|
+
if line =~ /\A(\S[^:]*):\z/
|
41
|
+
context = result[$1] = {}
|
42
|
+
elsif line =~ /\A ([^:]*): (.*)\z/
|
43
|
+
context[$1] = $2
|
44
|
+
elsif line =~ /\A([^:]*): (.*)\z/
|
45
|
+
result[$1] = $2
|
46
|
+
elsif line =~ /\A\s*(?:#|\z)/
|
47
|
+
# comment / empty
|
48
|
+
else
|
49
|
+
raise "Unexpected config line #{line.inspect}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
result
|
54
|
+
end
|
55
|
+
|
56
|
+
def write(data)
|
57
|
+
Dir.mkdir(@root) unless Dir.exist?(@root)
|
58
|
+
|
59
|
+
tempfile = File.join(@root, ".config.#{Process.pid}")
|
60
|
+
File.open(tempfile, "w", 0644) do |f|
|
61
|
+
data.each do |key, value|
|
62
|
+
next if value.is_a?(Hash)
|
63
|
+
f.puts("#{key}: #{value}")
|
64
|
+
end
|
65
|
+
|
66
|
+
data.each do |key, value|
|
67
|
+
next unless value.is_a?(Hash)
|
68
|
+
f.puts
|
69
|
+
f.puts("#{key}:")
|
70
|
+
value.each do |subkey, subvalue|
|
71
|
+
f.puts(" #{subkey}: #{subvalue}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
File.rename(tempfile, @path)
|
77
|
+
ensure
|
78
|
+
File.unlink(tempfile) if File.exist?(tempfile)
|
79
|
+
end
|
80
|
+
end
|