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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +74 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +39 -0
  5. data/exe/gel +13 -0
  6. data/lib/gel.rb +22 -0
  7. data/lib/gel/catalog.rb +153 -0
  8. data/lib/gel/catalog/common.rb +82 -0
  9. data/lib/gel/catalog/compact_index.rb +152 -0
  10. data/lib/gel/catalog/dependency_index.rb +125 -0
  11. data/lib/gel/catalog/legacy_index.rb +157 -0
  12. data/lib/gel/catalog/marshal_hacks.rb +16 -0
  13. data/lib/gel/command.rb +86 -0
  14. data/lib/gel/command/config.rb +11 -0
  15. data/lib/gel/command/env.rb +7 -0
  16. data/lib/gel/command/exec.rb +66 -0
  17. data/lib/gel/command/help.rb +7 -0
  18. data/lib/gel/command/install.rb +7 -0
  19. data/lib/gel/command/install_gem.rb +16 -0
  20. data/lib/gel/command/lock.rb +34 -0
  21. data/lib/gel/command/ruby.rb +10 -0
  22. data/lib/gel/command/shell_setup.rb +25 -0
  23. data/lib/gel/command/stub.rb +12 -0
  24. data/lib/gel/command/update.rb +11 -0
  25. data/lib/gel/compatibility.rb +4 -0
  26. data/lib/gel/compatibility/bundler.rb +54 -0
  27. data/lib/gel/compatibility/bundler/cli.rb +6 -0
  28. data/lib/gel/compatibility/bundler/friendly_errors.rb +3 -0
  29. data/lib/gel/compatibility/bundler/setup.rb +4 -0
  30. data/lib/gel/compatibility/rubygems.rb +192 -0
  31. data/lib/gel/compatibility/rubygems/command.rb +4 -0
  32. data/lib/gel/compatibility/rubygems/dependency_installer.rb +0 -0
  33. data/lib/gel/compatibility/rubygems/gem_runner.rb +6 -0
  34. data/lib/gel/config.rb +80 -0
  35. data/lib/gel/db.rb +294 -0
  36. data/lib/gel/direct_gem.rb +29 -0
  37. data/lib/gel/environment.rb +592 -0
  38. data/lib/gel/error.rb +104 -0
  39. data/lib/gel/gemfile_parser.rb +144 -0
  40. data/lib/gel/gemspec_parser.rb +95 -0
  41. data/lib/gel/git_catalog.rb +38 -0
  42. data/lib/gel/git_depot.rb +119 -0
  43. data/lib/gel/httpool.rb +148 -0
  44. data/lib/gel/installer.rb +251 -0
  45. data/lib/gel/lock_loader.rb +164 -0
  46. data/lib/gel/lock_parser.rb +64 -0
  47. data/lib/gel/locked_store.rb +126 -0
  48. data/lib/gel/multi_store.rb +96 -0
  49. data/lib/gel/package.rb +156 -0
  50. data/lib/gel/package/inspector.rb +23 -0
  51. data/lib/gel/package/installer.rb +267 -0
  52. data/lib/gel/path_catalog.rb +44 -0
  53. data/lib/gel/pinboard.rb +140 -0
  54. data/lib/gel/pub_grub/preference_strategy.rb +82 -0
  55. data/lib/gel/pub_grub/source.rb +153 -0
  56. data/lib/gel/runtime.rb +27 -0
  57. data/lib/gel/store.rb +205 -0
  58. data/lib/gel/store_catalog.rb +31 -0
  59. data/lib/gel/store_gem.rb +80 -0
  60. data/lib/gel/stub_set.rb +51 -0
  61. data/lib/gel/support/gem_platform.rb +225 -0
  62. data/lib/gel/support/gem_requirement.rb +264 -0
  63. data/lib/gel/support/gem_version.rb +398 -0
  64. data/lib/gel/support/tar.rb +13 -0
  65. data/lib/gel/support/tar/tar_header.rb +229 -0
  66. data/lib/gel/support/tar/tar_reader.rb +123 -0
  67. data/lib/gel/support/tar/tar_reader/entry.rb +154 -0
  68. data/lib/gel/support/tar/tar_writer.rb +339 -0
  69. data/lib/gel/tail_file.rb +205 -0
  70. data/lib/gel/version.rb +5 -0
  71. data/lib/gel/work_pool.rb +143 -0
  72. data/man/man1/gel-exec.1 +16 -0
  73. data/man/man1/gel-install.1 +16 -0
  74. data/man/man1/gel.1 +30 -0
  75. metadata +131 -0
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::Help < Gel::Command
4
+ def run(command_line)
5
+ raise "TODO"
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::Install < Gel::Command
4
+ def run(command_line)
5
+ Gel::Environment.activate(install: true, output: $stderr)
6
+ end
7
+ end
@@ -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,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::Ruby < Gel::Command
4
+ def run(command_line)
5
+ command = Gel::Command::Exec.new
6
+ command.run(["ruby", *command_line])
7
+ ensure
8
+ self.reraise = command.reraise if command
9
+ end
10
+ 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,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ $:[0, 0] = File.expand_path("compatibility", __dir__)
4
+ require_relative "compatibility/rubygems"
@@ -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,3 @@
1
+ def Bundler.with_friendly_errors
2
+ yield
3
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../bundler"
4
+ Bundler.setup
@@ -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"
@@ -0,0 +1,4 @@
1
+ module Gem::Command
2
+ def self.build_args=(value)
3
+ end
4
+ end
@@ -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
@@ -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