gel 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gel::PubGrub
|
4
|
+
class PreferenceStrategy
|
5
|
+
def initialize(loader, overrides, bump: :major, strict: false)
|
6
|
+
@loader = loader
|
7
|
+
@overrides = overrides
|
8
|
+
@bump = bump
|
9
|
+
@strict = strict
|
10
|
+
end
|
11
|
+
|
12
|
+
# Overrides first, then packages for which we have a preference (and
|
13
|
+
# that preference is still in play), then everything else.
|
14
|
+
def package_priority(package, versions)
|
15
|
+
if package.name =~ /^~/
|
16
|
+
-1000
|
17
|
+
elsif @overrides.key?(package.name)
|
18
|
+
-100
|
19
|
+
elsif range = ranges[package.name]
|
20
|
+
yes, no = versions.partition { |version| range.satisfied_by?(version) }
|
21
|
+
if yes.any? && no.any?
|
22
|
+
-50
|
23
|
+
else
|
24
|
+
0
|
25
|
+
end
|
26
|
+
else
|
27
|
+
0
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def sort_versions_by_preferred(package, versions)
|
32
|
+
return versions if @strict # already filtered
|
33
|
+
return versions unless range = ranges[package.name]
|
34
|
+
versions.partition { |version| range.satisfied_by?(version) }.inject(:+)
|
35
|
+
end
|
36
|
+
|
37
|
+
def constraints
|
38
|
+
ranges = @strict ? self.ranges : @overrides
|
39
|
+
|
40
|
+
result = {}
|
41
|
+
ranges.each do |package_name, range|
|
42
|
+
result[package_name] = [range] if range
|
43
|
+
end
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def ranges
|
50
|
+
@ranges ||=
|
51
|
+
begin
|
52
|
+
result = @overrides.dup
|
53
|
+
@loader.each_gem do |section, body, name, version, platform, deps|
|
54
|
+
next if @overrides.key?(name)
|
55
|
+
|
56
|
+
result[name] = range_for(version, @bump)
|
57
|
+
end
|
58
|
+
result.delete_if { |_, v| !v }
|
59
|
+
result
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def range_for(version, bump)
|
64
|
+
version = Gel::Support::GemVersion.new(version)
|
65
|
+
|
66
|
+
case bump
|
67
|
+
when :major
|
68
|
+
Gel::Support::GemRequirement.new ">= #{version}"
|
69
|
+
when :minor
|
70
|
+
next_major = version.bump
|
71
|
+
next_major = next_major.bump while next_major.segments.size > 2
|
72
|
+
Gel::Support::GemRequirement.new [">= #{version}", "< #{next_major}"]
|
73
|
+
when :patch
|
74
|
+
next_minor = version.bump
|
75
|
+
next_minor = next_minor.bump while next_minor.segments.size > 3
|
76
|
+
Gel::Support::GemRequirement.new [">= #{version}", "< #{next_minor}"]
|
77
|
+
when :hold
|
78
|
+
Gel::Support::GemRequirement.new "= #{version}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pub_grub"
|
4
|
+
require "pub_grub/basic_package_source"
|
5
|
+
require "pub_grub/rubygems"
|
6
|
+
|
7
|
+
module Gel::PubGrub
|
8
|
+
class Source < ::PubGrub::BasicPackageSource
|
9
|
+
Spec = Struct.new(:catalog, :name, :version, :info) do
|
10
|
+
def gem_version
|
11
|
+
@gem_version ||= Gel::Support::GemVersion.new(version)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :root, :root_version
|
16
|
+
|
17
|
+
def initialize(gemfile, catalogs, active_platforms, preference_strategy)
|
18
|
+
@gemfile = gemfile
|
19
|
+
@catalogs = catalogs
|
20
|
+
@active_platforms = active_platforms
|
21
|
+
@preference_strategy = preference_strategy
|
22
|
+
|
23
|
+
@packages = Hash.new {|h, k| h[k] = PubGrub::Package.new(k) }
|
24
|
+
@root = PubGrub::Package.root
|
25
|
+
@root_version = PubGrub::Package.root_version
|
26
|
+
|
27
|
+
@cached_specs = Hash.new { |h, k| h[k] = {} }
|
28
|
+
@specs_by_package_version = {}
|
29
|
+
|
30
|
+
super()
|
31
|
+
end
|
32
|
+
|
33
|
+
def spec_for_version(package, version)
|
34
|
+
if package.name =~ /^~/
|
35
|
+
return Spec.new(nil, package.name, version, [])
|
36
|
+
end
|
37
|
+
|
38
|
+
@specs_by_package_version[package][version.to_s]
|
39
|
+
end
|
40
|
+
|
41
|
+
def all_versions_for(package)
|
42
|
+
if package.name =~ /^~/
|
43
|
+
return [Gem::Version.new("0")]
|
44
|
+
end
|
45
|
+
|
46
|
+
fetch_package_info(package)
|
47
|
+
|
48
|
+
@specs_by_package_version[package].values.map(&:gem_version)
|
49
|
+
end
|
50
|
+
|
51
|
+
def sort_versions_by_preferred(package, sorted_versions)
|
52
|
+
sorted_versions = sorted_versions.reverse
|
53
|
+
|
54
|
+
if @preference_strategy
|
55
|
+
sorted_versions = @preference_strategy.sort_versions_by_preferred(package, sorted_versions)
|
56
|
+
end
|
57
|
+
|
58
|
+
prereleases, releases = sorted_versions.partition(&:prerelease?)
|
59
|
+
releases.concat(prereleases)
|
60
|
+
end
|
61
|
+
|
62
|
+
def dependencies_for(package, version)
|
63
|
+
deps = {}
|
64
|
+
|
65
|
+
case package.name
|
66
|
+
when "~arguments"
|
67
|
+
if @preference_strategy
|
68
|
+
@preference_strategy.constraints.each do |name, constraints|
|
69
|
+
deps[name] ||= []
|
70
|
+
deps[name].concat constraints.flatten
|
71
|
+
end
|
72
|
+
end
|
73
|
+
when /^~/
|
74
|
+
raise "Unknown pseudo-package"
|
75
|
+
else
|
76
|
+
fetch_package_info(package) # probably already done, can't hurt
|
77
|
+
|
78
|
+
spec = @specs_by_package_version[package][version.to_s]
|
79
|
+
info = spec.info
|
80
|
+
info = info.select { |p, i| @active_platforms.include?(p) }
|
81
|
+
|
82
|
+
info.flat_map { |_, i| i[:dependencies] }.each do |n, cs|
|
83
|
+
deps[n] ||= []
|
84
|
+
deps[n].concat cs
|
85
|
+
end
|
86
|
+
|
87
|
+
# FIXME: ruby_constraints ???
|
88
|
+
end
|
89
|
+
|
90
|
+
deps
|
91
|
+
end
|
92
|
+
|
93
|
+
def root_dependencies
|
94
|
+
deps = { "~arguments" => [] }
|
95
|
+
|
96
|
+
@gemfile.gems.select do |_, _, options|
|
97
|
+
next true unless platforms = options[:platforms]
|
98
|
+
!([*platforms] & [:ruby, :mri]).empty?
|
99
|
+
end.each do |name, constraints, _|
|
100
|
+
deps[name] ||= []
|
101
|
+
deps[name].concat constraints.flatten
|
102
|
+
end
|
103
|
+
|
104
|
+
deps.values.each(&:uniq!)
|
105
|
+
|
106
|
+
deps
|
107
|
+
end
|
108
|
+
|
109
|
+
def parse_dependency(package, requirement)
|
110
|
+
::PubGrub::VersionConstraint.new(@packages[package], range: to_range(requirement))
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def fetch_package_info(package)
|
116
|
+
return if @specs_by_package_version.key?(package)
|
117
|
+
|
118
|
+
specs = []
|
119
|
+
@catalogs.each do |catalog|
|
120
|
+
if catalog.nil?
|
121
|
+
break unless specs.empty?
|
122
|
+
next
|
123
|
+
end
|
124
|
+
|
125
|
+
if info = catalog.gem_info(package.name)
|
126
|
+
@cached_specs[catalog][package.name] ||=
|
127
|
+
begin
|
128
|
+
grouped_versions = info.to_a.map do |full_version, attributes|
|
129
|
+
version, platform = full_version.split("-", 2)
|
130
|
+
platform ||= "ruby"
|
131
|
+
[version, platform, attributes]
|
132
|
+
end.group_by(&:first)
|
133
|
+
|
134
|
+
grouped_versions.map { |version, tuples| Spec.new(catalog, package.name, version, tuples.map { |_, p, a| [p, a] }) }
|
135
|
+
end
|
136
|
+
|
137
|
+
specs.concat @cached_specs[catalog][package.name]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
@specs_by_package_version[package] = {}
|
142
|
+
specs.each do |spec|
|
143
|
+
# TODO: are we going to find specs in multiple catalogs this way?
|
144
|
+
@specs_by_package_version[package][spec.version] = spec
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_range(constraints)
|
149
|
+
requirement = Gel::Support::GemRequirement.new(constraints)
|
150
|
+
::PubGrub::RubyGems.requirement_to_range(requirement)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/lib/gel/runtime.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../gel"
|
4
|
+
|
5
|
+
dir = ENV["GEL_STORE"] || "~/.local/gel"
|
6
|
+
dir = File.expand_path(dir)
|
7
|
+
|
8
|
+
unless Dir.exist?(dir)
|
9
|
+
require "fileutils"
|
10
|
+
FileUtils.mkdir_p(dir)
|
11
|
+
end
|
12
|
+
|
13
|
+
dir = File.realpath(dir)
|
14
|
+
|
15
|
+
stores = {}
|
16
|
+
Gel::Environment.store_set.each do |key|
|
17
|
+
subdir = File.join(dir, key)
|
18
|
+
Dir.mkdir(subdir) unless Dir.exist?(subdir)
|
19
|
+
stores[key] = Gel::Store.new(subdir)
|
20
|
+
end
|
21
|
+
store = Gel::MultiStore.new(dir, stores)
|
22
|
+
|
23
|
+
Gel::Environment.open(Gel::LockedStore.new(store))
|
24
|
+
|
25
|
+
if ENV["GEL_LOCKFILE"] && ENV["GEL_LOCKFILE"] != ""
|
26
|
+
Gel::Environment.activate(output: $stderr)
|
27
|
+
end
|
data/lib/gel/store.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "db"
|
4
|
+
|
5
|
+
class Gel::Store
|
6
|
+
attr_reader :root
|
7
|
+
attr_reader :monitor
|
8
|
+
|
9
|
+
def initialize(root)
|
10
|
+
@root = File.realpath(File.expand_path(root))
|
11
|
+
@primary_db = Gel::DB.new(root, "store")
|
12
|
+
@lib_db = Gel::DB.new(root, "libs")
|
13
|
+
@rlib_db = Gel::DB::File.new(root, "meta")
|
14
|
+
|
15
|
+
@monitor = Monitor.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def stub_set
|
19
|
+
@stub_set ||= Gel::StubSet.new(@root)
|
20
|
+
end
|
21
|
+
|
22
|
+
def paths
|
23
|
+
[@root.dup]
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_gem(name, version, bindir, executables, require_paths, dependencies, extensions)
|
27
|
+
name = normalize_string(name)
|
28
|
+
version = normalize_string(version)
|
29
|
+
bindir = normalize_string(bindir)
|
30
|
+
executables = executables.map { |v| normalize_string(v) }
|
31
|
+
require_paths = require_paths.map { |v| normalize_string(v) }
|
32
|
+
_dependencies = {}
|
33
|
+
dependencies.each do |key, dep|
|
34
|
+
_dependencies[normalize_string(key)] = dep.map { |pair| pair.map { |v| normalize_string(v) } }
|
35
|
+
end
|
36
|
+
dependencies = _dependencies
|
37
|
+
extensions = !!extensions
|
38
|
+
|
39
|
+
@primary_db.writing do
|
40
|
+
vs = @primary_db["v/#{name}"] || []
|
41
|
+
raise "already installed" if vs.include?(version)
|
42
|
+
vs << version
|
43
|
+
vs.sort_by! { |v| Gel::Support::GemVersion.new(v) }
|
44
|
+
vs.reverse!
|
45
|
+
@primary_db["v/#{name}"] = vs
|
46
|
+
|
47
|
+
d = {}
|
48
|
+
d[:bindir] = bindir unless bindir == "bin"
|
49
|
+
d[:executables] = executables unless executables.empty?
|
50
|
+
d[:require_paths] = require_paths unless require_paths == ["lib"]
|
51
|
+
d[:dependencies] = dependencies unless dependencies.empty?
|
52
|
+
d[:extensions] = extensions if extensions
|
53
|
+
@primary_db["i/#{name}/#{version}"] = d
|
54
|
+
|
55
|
+
yield if block_given?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_lib(name, version, files)
|
60
|
+
name = normalize_string(name)
|
61
|
+
version = version.is_a?(Array) ? version.map { |v| normalize_string(v) } : normalize_string(version)
|
62
|
+
files = files.map { |v| normalize_string(v) }
|
63
|
+
|
64
|
+
@lib_db.writing do
|
65
|
+
@rlib_db.writing do |rst|
|
66
|
+
files.each do |file|
|
67
|
+
h = @lib_db[file] || {}
|
68
|
+
d = h[name] || []
|
69
|
+
raise "already installed" if d.include?(version)
|
70
|
+
d << version
|
71
|
+
h[name] = d.sort_by.with_index { |(v, _), idx| [Gel::Support::GemVersion.new(v), -idx] }.reverse
|
72
|
+
@lib_db[file] = h
|
73
|
+
end
|
74
|
+
|
75
|
+
v, d = version
|
76
|
+
ls = @rlib_db["#{name}-#{v}"] || []
|
77
|
+
unless sls = ls.assoc(d)
|
78
|
+
sls = [d, []]
|
79
|
+
ls << sls
|
80
|
+
end
|
81
|
+
sls.last.concat files
|
82
|
+
@rlib_db["#{name}-#{v}"] = ls
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def gem?(name, version, _platform = nil)
|
88
|
+
!!gem_info(name, version)
|
89
|
+
end
|
90
|
+
|
91
|
+
def gem(name, version)
|
92
|
+
info = gem_info(name, version)
|
93
|
+
info && _gem(name, version, info)
|
94
|
+
end
|
95
|
+
|
96
|
+
def gems(name_version_pairs)
|
97
|
+
result = {}
|
98
|
+
|
99
|
+
name_version_pairs.each do |name, version|
|
100
|
+
if info = gem_info(name, version)
|
101
|
+
result[name] = _gem(name, version, info)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
result
|
106
|
+
end
|
107
|
+
|
108
|
+
def gem_root(name, version)
|
109
|
+
"#{@root}/gems/#{name}-#{version}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def extension_path(name, version)
|
113
|
+
"#{@root}/ext/#{name}-#{version}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def prepare(versions)
|
117
|
+
end
|
118
|
+
|
119
|
+
def libs_for_gems(versions)
|
120
|
+
@rlib_db.reading do
|
121
|
+
versions.each do |name, version|
|
122
|
+
if libs = @rlib_db["#{name}-#{version}"]
|
123
|
+
yield name, version, libs
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def gems_for_lib(file)
|
130
|
+
if h = @lib_db[file]
|
131
|
+
h.each do |name, versions|
|
132
|
+
versions.each do |version|
|
133
|
+
if version.is_a?(Array)
|
134
|
+
version, subdir = version
|
135
|
+
yield gem(name, version), subdir
|
136
|
+
else
|
137
|
+
yield gem(name, version)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def each(gem_name = nil)
|
145
|
+
return enum_for(__callee__, gem_name) unless block_given?
|
146
|
+
|
147
|
+
if gem_name
|
148
|
+
@primary_db.reading do
|
149
|
+
return unless vs = @primary_db["v/#{gem_name}"]
|
150
|
+
vs.each do |version|
|
151
|
+
if info = @primary_db["i/#{gem_name}/#{version}"]
|
152
|
+
yield _gem(gem_name, version, info)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
else
|
157
|
+
gem_names = []
|
158
|
+
@primary_db.each_key do |k|
|
159
|
+
gem_names << $1 if k =~ /\Av\/(.*)\z/
|
160
|
+
end
|
161
|
+
|
162
|
+
block = Proc.new
|
163
|
+
gem_names.each do |n|
|
164
|
+
each(n, &block)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def inspect
|
170
|
+
content = each.map { |g| "#{g.name}-#{g.version}" }
|
171
|
+
content = ["(none)"] if content.empty?
|
172
|
+
content.sort!
|
173
|
+
|
174
|
+
"#<#{self.class} root=#{@root.inspect} content=#{content.join(",")}>"
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
|
179
|
+
def _gem(name, version, info)
|
180
|
+
info = inflate_info(info)
|
181
|
+
extensions = extension_path(name, version) if info[:extensions]
|
182
|
+
Gel::StoreGem.new(gem_root(name, version), name, version, extensions, info)
|
183
|
+
end
|
184
|
+
|
185
|
+
def gem_info(name, version)
|
186
|
+
@primary_db["i/#{name}/#{version}"]
|
187
|
+
end
|
188
|
+
|
189
|
+
def inflate_info(d)
|
190
|
+
d = d.dup
|
191
|
+
d[:bindir] = "bin" unless d.key?(:bindir)
|
192
|
+
d[:executables] = [] unless d.key?(:executables)
|
193
|
+
d[:require_paths] = ["lib"] unless d.key?(:require_paths)
|
194
|
+
d[:dependencies] = {} unless d.key?(:dependencies)
|
195
|
+
d
|
196
|
+
end
|
197
|
+
|
198
|
+
# Almost every string we store is pure ASCII, and binary strings
|
199
|
+
# marshal better.
|
200
|
+
def normalize_string(str)
|
201
|
+
str = str.to_s
|
202
|
+
str = str.b if str.ascii_only?
|
203
|
+
str
|
204
|
+
end
|
205
|
+
end
|